AWS DevOps Agent に Lambda のタイムアウトを調査させて、修正プルリクエストまで作らせてみた

AWS DevOps Agent に Lambda のタイムアウトを調査させて、修正プルリクエストまで作らせてみた

GitHub MCP サーバーを GitHub App の OAuth 3LO で接続することで、Lambda のタイムアウトを調査させて修正プルリクエストの作成まで完走させられた。
2026.08.05

こんにちは、製造ビジネステクノロジー部の若槻です。

AWS DevOps Agent は障害を調査して根本原因を特定してくれますが、特定した原因を直すプルリクエストまで作らせられるのかが気になっていました。

そこで、意図的にタイムアウトする Lambda 関数を用意して、エージェントに「調査して修正プルリクエストを作って」と依頼してみました。

結論

  • ネイティブの GitHub 連携アクセスレベル「読み取りと書き込み」で登録していても、エージェントに渡る GitHub ツールは読み取り専用の 14 個だけでした。プルリクエストは作れません。これは連携が古いせいではなく仕様です
  • 修正プルリクエストを作らせるには GitHub 公式のリモート MCP サーバーhttps://api.githubcopilot.com/mcp/)を別途接続する必要があります
  • MCP サーバーの認証は GitHub App の OAuth 3LO が使えます。OAuth App の repo スコープより権限を絞れます
  • ただし OAuth 3LO の MCP サーバー登録は CloudFormation / AWS CDK では作成できません。IaC 化できるのは Association(ツール許可リスト)だけです

検証構成

Agent Space は既存のものを使い回しています。Agent Space 自体の作成は以下の記事で扱っています。

https://dev.classmethod.jp/articles/aws-devops-agent-cdk-implementation-github-integration/

検証対象の Lambda 関数

ハンドラーの処理時間(10 秒)より短いタイムアウト値(3 秒)を設定して、意図的に Status: timeout を発生させます。

lib/constructs/devops-agent-pr-verification/slow-task-function/function.ts
const PROCESSING_SECONDS = 10;

const sleep = (milliseconds: number): Promise<void> =>
  new Promise((resolve) => setTimeout(resolve, milliseconds));

/**
 * 長時間処理を模した検証用ハンドラー
 *
 * 関数のタイムアウト値より長く動作させることで、意図的に Task timed out を発生させる。
 */
export const handler = async (): Promise<void> => {
  console.log(
    `Start processing. This task takes ${PROCESSING_SECONDS} seconds.`,
  );

  await sleep(PROCESSING_SECONDS * 1000);

  console.log("Finished processing.");
};
lib/constructs/devops-agent-pr-verification/slow-task-function/index.ts
import * as cdk from "aws-cdk-lib";
import * as nodejs from "aws-cdk-lib/aws-lambda-nodejs";
import * as logs from "aws-cdk-lib/aws-logs";
import { Construct } from "constructs";

/**
 * 検証用 Lambda 関数の実装
 *
 * ハンドラーの処理時間(10 秒)より短いタイムアウト値を設定することで、
 * 意図的に Task timed out を発生させる。DevOps Agent にこの障害を調査させ、
 * 修正プルリクエストを作成させるための検証用リソース。検証専用。
 */
export class SlowTaskFunctionConstruct extends Construct {
  public readonly function: nodejs.NodejsFunction;

  constructor(scope: Construct, id: string) {
    super(scope, id);

    const logGroup = new logs.LogGroup(this, "LogGroup", {
      retention: logs.RetentionDays.ONE_WEEK,
      removalPolicy: cdk.RemovalPolicy.DESTROY, // 検証用のため、スタック削除時に削除する
    });

    this.function = new nodejs.NodejsFunction(this, "Default", {
      entry:
        "lib/constructs/devops-agent-pr-verification/slow-task-function/function.ts",
      handler: "handler",
      timeout: cdk.Duration.seconds(3), // 処理時間より短く、意図的にタイムアウトさせる
      logGroup,
    });
  }
}

デプロイして 5 回呼び出すと、すべてタイムアウトしました。

for i in 1 2 3 4 5; do
  aws lambda invoke --function-name "$FUNCTION_NAME" --payload '{}' /dev/null \
    --query '{StatusCode:StatusCode,FunctionError:FunctionError}' --output text
done
Unhandled	200
Unhandled	200
Unhandled	200
Unhandled	200
Unhandled	200

ログを見ると Duration: 3000.00 ms / Status: timeout です。

aws logs tail "$LOG_GROUP_NAME" --since 15m
INFO	Start processing. This task takes 10 seconds.
END RequestId: fde2c844-72d9-4d28-8451-e3d0ebed9445
REPORT RequestId: fde2c844-72d9-4d28-8451-e3d0ebed9445	Duration: 3000.00 ms
  Billed Duration: 3193 ms	Memory Size: 128 MB	Max Memory Used: 76 MB
  Init Duration: 192.36 ms	Status: timeout

なお Finished processing. は 1 度も出力されていません。処理が終わる前に強制終了されています。

検証 1:ネイティブの GitHub 連携だけで依頼する

まずは MCP サーバーを接続しない状態で依頼します。この Agent Space のネイティブ GitHub 連携は、マネジメントコンソールの 機能プロバイダー でアクセスレベルが 読み取りと書き込み と表示されています。


機能プロバイダーの登録一覧。GitHub は「読み取りと書き込み」だが、エージェントに渡るツールは読み取り専用だった(MCP Server は後から登録したもの)

エージェントに使えるツールを聞いてみました。

利用可能な GitHub 関連ツールの一覧を、ツール名と用途の表で正確に教えてください。

返ってきたのは 14 個で、すべて読み取り専用でした。

ツール名 用途
get_github_file リポジトリ内の特定ファイルの内容を取得
get_github_pipeline_files .github/workflows/ 配下のワークフローファイルを取得・一覧表示
get_github_workflow_environments ワークフローの環境設定とデプロイ履歴を取得
get_github_workflow_run_logs 特定のワークフロー実行の完全なログを取得
list_github_workflow_runs 特定ワークフローの実行履歴一覧を取得
list_github_workflows リポジトリ内のすべてのワークフロー一覧を取得
list_repositories Agent Space に紐づくリポジトリの一覧を取得
git_log コミット履歴を取得
git_diff 2 つの git リファレンス間の差分を表示
list_branches リポジトリのブランチ一覧を取得
repo_ls ディレクトリ構造をツリー形式で表示
repo_glob glob パターンでファイルを検索
repo_grep 正規表現でコード内のパターンを検索
repo_read ファイルの内容を読み取り

すべて読み取り専用です。書き込み操作(ブランチ作成・ファイル更新・PR作成など)は現在のツールセットには含まれていません。

この状態で調査と PR 作成を依頼しました。

Lambda 関数 DevOpsAgentPrVerification-SlowTaskFunction...(ap-northeast-1)がタイムアウトしています。CloudWatch Logs を確認して原因を特定し、この関数を定義している GitHub リポジトリ cm-rwakatsuki/security-infra のソースコードを調べて、根本原因を修正するプルリクエストを作成してください。

調査は完璧でした。CloudWatch Logs Insights でタイムアウトを確認し、GitHub のソースコードから該当箇所を特定しています。

項目
Lambda タイムアウト設定 3 秒
ハンドラーの処理時間 10 秒
タイムアウト率(直近) 100%(5/5 回)

エージェントは修正すべきファイルと行まで言い当てました。

lib/constructs/devops-agent-pr-verification/slow-task-function/index.ts lines 24-30

一方でプルリクエストは作れず、手動で作る手順を案内して終わりました

GitHub への書き込み操作(ブランチ作成・ファイルコミット・PR作成)は、現在のエージェントの機能範囲外となっています。読み取り専用の GitHub ツールのみ利用可能です。

エージェントジャーナルで、この調査に使われたツールを確認します。

aws devops-agent list-journal-records \
  --agent-space-id <agent-space-id> \
  --execution-id <execution-id> \
  --order ASC

呼ばれたツールは以下の通りで、書き込み系は 1 つもありません

ツール 呼び出し回数
use_aws 9
repo_read 6
query_cloudwatch_logs 5
repo_ls / gather_context / skill_read 各 3
get_github_file / datetime 各 2
repo_grep / git_log / list_associations 各 1

コンソールに表示される「読み取りと書き込み」は GitHub App にインストールされている権限のことで、エージェントの調査チャットに渡されるツールセットとは別でした。ドキュメントの権限表を読むと、Contents: Read and write の Write は「エージェントが修正を提案する」ためと書かれています。

Contents | Read and write | Read repository source code for code review analysis and dependency mapping. Write access enables the agent to propose fixes for identified issues.
Connecting GitHub

「連携が古いから」ではなかった

この Agent Space の GitHub 連携は少し前に設定したものだったので、「あとから追加された権限を承認していないだけではないか」と疑いました。ドキュメントにも次の注意書きがあります。

Until you accept a permission update, AWS DevOps Agent continues to operate with the previously granted permissions.

しかし、そうではありませんでした。

  1. GitHub App の権限は最新だったhttps://github.com/settings/installations で AWS DevOps Agent のインストールを見ると、権限は Read access to metadataRead and write access to actions, checks, code, commit statuses, issues, pull requests, and workflows で、Permission updates requested の表示もありません
  2. 新しいチャットでも同じだった。別のチャットでツール定義を確認させても、組み込みツールは同じ 14 個で「ブランチ作成・ファイル書き込み・コミット・プルリクエスト作成ができるものは 1 つもありません」という回答でした
  3. そもそも設計がそうなっている。AWS の機能ページには、修正コードの実装は別のエージェントに任せる前提だと書かれています

AWS DevOps Agent also provides agent-ready instructions that can be implemented by another frontier agent
Frontier agent – AWS DevOps Agent

DevOps Agent は「調査して修正指示(agent-ready instructions)を出す側」で、コードを書くのは Kiro のような別のエージェント、という役割分担です。GitHub App が書き込み権限を持っていても、調査チャットに書き込みツールが降りてこないのは仕様どおりということになります。

そして、その「別のエージェント」の代わりに GitHub MCP サーバーを直接持たせれば、DevOps Agent 自身に書かせられるというのが以降の話です。

GitHub MCP サーバーを接続する

AWS の Cloud Operations ブログでは、修正 PR を作らせるために GitHub 公式のリモート MCP サーバーを接続する構成が紹介されています。こちらは PAT(API キー認証)を使う手順ですが、今回は GitHub App を使った OAuth 3LO で接続しました。

認証方式の選択肢

aws devops-agent register-service --service mcpserverauthorizationConfig はタグ付きユニオンで、5 種類ありました。

oAuthClientCredentials | oAuth3LO | apiKey | bearerToken | authorizationDiscovery

一方 AWS::DevOpsAgent::Service が公開しているのは apiKeyoAuthClientCredentials だけです(aws-cdk-lib 2.257.0 で確認)。

認証方式 AWS CLI CloudFormation / CDK 長期トークン
apiKey 必要(PAT)
oAuthClientCredentials 不要
oAuth3LO 不要
bearerToken 必要
authorizationDiscovery 不要

oAuth3LOreturnToEndpoint に AWS コンソールのドメインを要求するため、実質ブラウザでの対話登録が前提です。IaC で完結させたいなら apiKey(PAT)、長期トークンを持ちたくないなら oAuth3LO というトレードオフになります。

今回は長期トークンを持ちたくなかったので oAuth3LO を選びました。

GitHub App を作成する

OAuth App ではなく GitHub App を使うと、repo スコープ(全リポジトリの read/write)ではなく App の permissions とインストール先リポジトリで権限を絞れます。GitHub App も Client ID / Client Secret を持ち、user access token を OAuth で発行できるので、3LO の設定にそのまま流用できます。

付与した permissions は 3 つだけです。

種別 権限 アクセスレベル
Repository Metadata Read
Repository Contents Read and write
Repository Pull requests Read and write

インストール先は Only select repositoriessecurity-infra の 1 つに限定しました。Webhook は使わないので Active のチェックを外しています。


GitHub App のインストール設定。権限は 2 行だけで、対象リポジトリも 1 つに限定している

Callback URL には DevOps Agent のコントロールプレーンを指定します。この URL は MCP サーバー登録画面に表示されます。

https://api.prod.cp.aidevops.ap-northeast-1.api.aws/v1/register/mcpserver/callback

この登録は「GitHub が認可コードを渡してよい宛先」のホワイトリストです。登録しておかないと Authorize 画面にすら到達しません。実際の流れはこうなっていました。

  1. コンソールで登録を送信すると、DevOps Agent がブラウザを GitHub の認証 URL へリダイレクトする。このとき redirect_uri に自分のコントロールプレーンを付ける
https://github.com/login/oauth/authorize
  ?response_type=code
  &client_id=<client-id>
  &state=<state>
  &redirect_uri=https%3A%2F%2Fapi.prod.cp.aidevops.ap-northeast-1.api.aws%2Fv1%2Fregister%2Fmcpserver%2Fcallback
  1. GitHub が、受け取った redirect_uriApp に登録済みの Callback URL と一致するかを検証する
  2. 一致すれば Authorize 画面が出る。画面下部に Authorizing will redirect to https://api.prod.cp.aidevops.ap-northeast-1.api.aws と表示される
  3. 承認すると、GitHub がその URL へ ?code=...&state=... を付けてリダイレクトする
  4. DevOps Agent のコントロールプレーンが認可コードを受け取り、交換 URL へクライアントシークレットと一緒に投げて user access token を取得する。この token が以降の MCP サーバー呼び出しの Authorization: Bearer になる

redirect_uri を検証しない実装だと、攻撃者が宛先を書き換えたリンクを踏ませて認可コードを横取りできてしまいます。Callback URL の事前登録は、それを GitHub 側で塞ぐための仕組みです。

なお、API リファレンスの MCPServerOAuth3LOConfig には returnToEndpoint というフィールドがありますが、これは GitHub に登録する Callback URL とは別物なので注意が必要です。

何を指すか 設定する場所
Callback URL(redirect_uri GitHub が認可コードを渡す先。DevOps Agent のコントロールプレーン GitHub App 側
returnToEndpoint 認可フロー完了後にブラウザを戻す先。AWS コンソールのドメインでなければならない DevOps Agent 側(コンソールが自動で入れる)

リージョンが URL に含まれる点も注意です。Agent Space が ap-northeast-1 なら ap-northeast-1 版が必要です。今回は最初どちらのリージョンが使われるか分からなかったので、GitHub App 側に 2 つとも登録しておきました。


GitHub App に登録した Callback URL。GitHub App は複数登録できる

結果として使われたのは Agent Space のリージョンと一致する ap-northeast-1 版だけでした。us-east-1 版は不要だったので削除できます。

MCP サーバーを登録する

マネジメントコンソールの 機能プロバイダー → MCP Server → Register から、4 ステップのウィザードで登録します。

項目
名前 GitHubMcpServer
エンドポイント URL https://api.githubcopilot.com/mcp/
認証フロー OAuth 3LO
クライアント ID GitHub App の Client ID
クライアントシークレット GitHub App の Client secret
交換 URL https://github.com/login/oauth/access_token
認証 URL https://github.com/login/oauth/authorize
コードチャレンジサポート オフ(GitHub は PKCE 非対応)
スコープ 指定なし

ステップ 1 では名前とエンドポイント URL を指定します。


ステップ 1。エンドポイントは GitHub 公式リモート MCP サーバーの URL を指定する

ステップ 2 で認証フローを選びます。コンソールの説明文は「3 種類」となっていますが、選択肢は 4 つ表示されました。


ステップ 2。今回は OAuth 3LO を選択した

ステップ 3 が認証設定です。GitHub App の場合、実際の権限は App の permissions で決まるためスコープの指定は不要でした。また PKCE は GitHub が非対応なので、コードチャレンジサポートはオフのままにします。

そしてこの画面の下部に、先に触れた Callback URL の案内が出ます。


ステップ 3。ユーザーガイドに記載のない「許可されたコールバック URL を設定する」の案内が、この画面にだけ表示される

送信すると GitHub の認可画面に飛び、承認すると登録が完了します。

CLI で確認すると authorizationMethodoauth-3lo になっています。

aws devops-agent list-services --region ap-northeast-1
{
  "serviceId": "<service-id>",
  "serviceType": "mcpserver",
  "name": "GitHubMcpServer",
  "additionalServiceDetails": {
    "mcpserver": {
      "name": "GitHubMcpServer",
      "endpoint": "https://api.githubcopilot.com/mcp/",
      "authorizationMethod": "oauth-3lo",
      "description": "GitHub の公式リモート MCP サーバー。修正プルリクエストの作成に使用する。"
    }
  }
}

ツール許可リストを AWS CDK で設定する

Service の登録はコンソール限定でしたが、Association(ツール許可リスト)は AWS::DevOpsAgent::Association で作成できます。PR 作成用の接続設定として最低限必要なソースコードはこれだけです。

lib/constructs/devops-agent-pr-verification/github-mcp-association/index.ts
import * as devopsagent from "aws-cdk-lib/aws-devopsagent";
import { Construct } from "constructs";

export interface GitHubMcpServerProps {
  serviceId: string; // コンソールで OAuth 3LO 登録した GitHub MCP サーバーのサービス ID
  tools: string[]; // Agent Space に許可する MCP ツール
}

interface GitHubMcpAssociationConstructProps {
  agentSpaceId: string;
  gitHubMcpServer: GitHubMcpServerProps;
}

/**
 * GitHub MCP サーバーと Agent Space の関連付けの実装
 *
 * ネイティブの GitHub 連携が提供するツールは読み取り専用のため、修正プルリクエストを
 * 作成させるには GitHub MCP サーバーを別途接続する必要がある。
 * tools には MCP サーバーが公開しているツールのうち、この Agent Space に
 * 許可するものだけを指定する(ツール許可リスト)。
 * @see https://docs.aws.amazon.com/devopsagent/latest/userguide/configuring-integrations-and-knowledge-connecting-mcp-servers.html
 */
export class GitHubMcpAssociationConstruct extends Construct {
  public readonly association: devopsagent.CfnAssociation;

  constructor(
    scope: Construct,
    id: string,
    props: GitHubMcpAssociationConstructProps,
  ) {
    super(scope, id);

    const { agentSpaceId, gitHubMcpServer } = props;
    const { serviceId, tools } = gitHubMcpServer;

    this.association = new devopsagent.CfnAssociation(this, "Default", {
      agentSpaceId,
      serviceId,
      configuration: {
        mcpServer: {
          tools,
        },
      },
    });
  }
}

スタックはこれだけです。

lib/devops-agent-pr-verification-stack.ts
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";

import { AppParameter } from "../bin/parameter";
import { GitHubMcpAssociationConstruct } from "./constructs/devops-agent-pr-verification/github-mcp-association";
import { SlowTaskFunctionConstruct } from "./constructs/devops-agent-pr-verification/slow-task-function";

/**
 * DevOps Agent の修正プルリクエスト作成検証用スタック
 *
 * 意図的にタイムアウトする Lambda 関数を作成し、DevOps Agent に調査と
 * 修正プルリクエストの作成を行わせる。検証が終わったら cdk destroy で削除する。
 */
export class DevOpsAgentPrVerificationStack extends cdk.Stack {
  constructor(
    scope: Construct,
    id: string,
    props: AppParameter & cdk.StackProps,
  ) {
    super(scope, id, props);

    const { devOpsAgentPrVerification } = props;
    const { agentSpaceId, gitHubMcpServer } = devOpsAgentPrVerification;

    // 意図的にタイムアウトする Lambda 関数を作成
    new SlowTaskFunctionConstruct(this, "SlowTaskFunction");

    // GitHub MCP サーバーを Agent Space に関連付け(ツール許可リスト)
    new GitHubMcpAssociationConstruct(this, "GitHubMcpAssociation", {
      agentSpaceId,
      gitHubMcpServer,
    });
  }
}

許可するツールを絞る

GitHub MCP サーバーが公開しているツールは 47 個ありました。merge_pull_requestdelete_file のような危険なものも含まれます。

プルリクエストを作るのに必要な最低限は 4 つでした。

tools: [
  "create_branch",
  "create_or_update_file",
  "create_pull_request",
  "get_file_contents",
],

デプロイ後、CLI で許可リストを確認します。

aws devops-agent list-associations \
  --agent-space-id <agent-space-id> --region ap-northeast-1
{
  "associationId": "<association-id>",
  "serviceId": "<service-id>",
  "configuration": {
    "mcpserver": {
      "tools": [
        "create_branch",
        "create_or_update_file",
        "create_pull_request",
        "get_file_contents"
      ]
    }
  }
}

マネジメントコンソールの MCP サーバーツールを選択 画面でも、47 ツールのうち許可した分だけにチェックが入った状態になります。


MCP サーバーツールの選択画面。47 ツールのうち許可した 4 つだけがチェックされ、create_or_update_filedelete_file は外れている

検証 2:MCP サーバーを接続して依頼する

検証 1 とまったく同じ依頼を、新しいチャットで投げます。

Lambda 関数 DevOpsAgentPrVerification-SlowTaskFunction...(ap-northeast-1)がタイムアウトしています。CloudWatch Logs を確認して原因を特定し、この関数を定義している GitHub リポジトリ cm-rwakatsuki/security-infra のソースコードを調べて、根本原因を修正するプルリクエストを作成してください。ベースブランチは main です。

つまずいた点:create_or_update_file は日本語を壊す

最初の許可リストは get_file_contents / create_branch / create_or_update_file / create_pull_request の 4 つにしていました。この構成ではブランチ作成までは成功したものの、ファイルの更新で止まりました

ジャーナルを見ると、MCP ツールは組み込みの invoke_user_tool 経由で、サーバー名がプレフィックスされた形で呼ばれています。

TOOL_USE invoke_user_tool input={"tool_name": "GitHubMcpServer_create_branch",
  "arguments": {"owner": "cm-rwakatsuki", "repo": "security-infra",
  "branch": "fix/slow-task-function-timeout", "from_branch": "main"}}

ブランチはこれで実際に作られました。続く create_or_update_file の呼び出しで問題が起きています。

TOOL_USE invoke_user_tool input={"tool_name": "GitHubMcpServer_create_or_update_file",
  "arguments": "{\n  \"owner\": \"cm-rwakatsuki\", ...
  \"content\": \"aW1wb3J0ICogYXMgY2RrIGZyb20gImF3cy1jZGstbGliIjsK...

create_or_update_fileファイル全体の内容を base64 で渡す 仕様です。この呼び出しには 2 つの問題がありました。

  1. 引数の JSON が途中で切れた。base64 が 443 文字で終わっており、arguments の文字列が未終端のまま final_response に遷移していました。ツール結果のレコードはジャーナルにも残っていません
  2. 日本語が壊れた。切れた部分までをデコードすると、コメントがこうなっていました
/**
 * 日試フリ Lambda 関数の定逤
 *
 * 遍nioi利用生日言言(ב 秂)(什失贚)を使意してえくっに

正しくは以下です。

/**
 * 検証用 Lambda 関数の実装
 *
 * ハンドラーの処理時間(10 秒)より短いタイムアウト値を設定することで、

エージェントが自力で base64 エンコードするため、マルチバイト文字が化けています。「1 行だけ直したい」のにファイル全体を base64 で再生成させるのは相性が悪いということです。

push_files に差し替える

GitHub MCP サーバーには push_files という、プレーンテキストのまま複数ファイルをコミットできるツールがあります。base64 を経由しないので上記の問題を回避できます。

許可リストを差し替えました。

tools: [
  "create_branch",
  "create_pull_request",
  "get_file_contents",
  // create_or_update_file は content を base64 で渡す仕様でマルチバイト文字が
  // 壊れるため、プレーンテキストで渡せる push_files を使わせる
  "push_files",
],

AWS::DevOpsAgent::Service は更新不可でしたが、Association の Tools は Update requires: No interruption なので、許可リストは差分デプロイで切り替えられました。

npx cdk deploy DevOpsAgentPrVerification --context environment=dev
DevOpsAgentPrVerification | UPDATE_COMPLETE | AWS::DevOpsAgent::Association
 ✅  DevOpsAgentPrVerification
✨  Deployment time: 23.98s

プルリクエストが作られた

同じ依頼を投げ直したところ、調査からプルリクエスト作成まで完走しました

プルリクエストの作成が完了しました! 🎉

呼ばれた MCP ツールは 3 つで、いずれも許可リストに入れたものだけです。

MCP ツール 結果
GitHubMcpServer_create_branch fix/slow-task-function-timeout を作成
GitHubMcpServer_push_files 1 ファイル・1 行だけ変更してコミット
GitHubMcpServer_create_pull_request プルリクエストを作成

この実行で呼ばれたツール全体はこうなりました。読み取り系のネイティブツールで調査し、書き込みだけ invoke_user_tool 経由で MCP に流れています。

ツール 呼び出し回数
query_cloudwatch_logs 9
repo_read 5
invoke_user_tool 3
repo_ls / gather_context / skill_read / datetime 各 2
use_aws / search_user_tools / repo_grep 各 1

作られたプルリクエストを GitHub API で確認します。

curl -s -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.github+json" \
  https://api.github.com/repos/cm-rwakatsuki/security-infra/pulls/102
number: 102
title: fix: SlowTaskFunction のタイムアウト値を 3 秒から 15 秒に延長
state: open | draft: False
head: fix/slow-task-function-timeout -> main
commits: 1 | changed_files: 1 | + 1 / - 1

差分は狙いどおり 1 行だけで、日本語コメントも壊れていません

git diff origin/main..origin/fix/slow-task-function-timeout
--- a/lib/constructs/devops-agent-pr-verification/slow-task-function/index.ts
+++ b/lib/constructs/devops-agent-pr-verification/slow-task-function/index.ts
@@ -25,7 +25,7 @@ export class SlowTaskFunctionConstruct extends Construct {
        entry:
          "lib/constructs/devops-agent-pr-verification/slow-task-function/function.ts",
        handler: "handler",
-      timeout: cdk.Duration.seconds(3), // 処理時間より短く、意図的にタイムアウトさせる
+      timeout: cdk.Duration.seconds(15), // 処理時間より短く、意図的にタイムアウトさせる
        logGroup,
      });
    }

PR の本文もエージェントが書いていて、根本原因の表と変更差分、影響範囲まで含まれていました。

根本原因

CloudWatch Logs を調査した結果、以下の不一致が判明しました。

項目
設定タイムアウト値 3 秒
実際の処理時間 (PROCESSING_SECONDS) 10 秒

なお、コメントの文言(「処理時間より短く、意図的にタイムアウトさせる」)は変更後の値と矛盾したまま残っています。「タイムアウト値の行だけを変更してください」と指示したためですが、コードの意図を表すコメントの追従までは面倒を見てくれませんでした。

GitHub 側には App 経由と記録される

GitHub の PR 画面を見ると、コメントの署名が with devops-agent-github-mcp-... となっています。OAuth 3LO で発行された user access token は「ユーザーとして、この GitHub App 経由で」という扱いなので、誰の代理でどのアプリが操作したかが GitHub 側に残ります。


エージェントが作成したプルリクエスト。コメントの署名に「with (GitHub App 名)」が付き、差分は +1 -1 の 1 行のみ

検証結果まとめ

# 確認したこと 結果
1 ネイティブ GitHub 連携だけで PR を作れるか ❌ アクセスレベルが「読み取りと書き込み」でも、渡されるツールは読み取り専用 14 個
1' それは連携が古いせいか ❌ GitHub App の権限は最新(保留中の更新なし)。別チャットでも同結果。設計どおり
2 調査そのものの精度 ✅ タイムアウト率 100%(5/5)を突き止め、修正すべきファイルと行まで特定
3 GitHub MCP サーバーを OAuth 3LO で登録できるか ✅ GitHub App の Client ID / Secret で登録でき、長期トークン不要
4 MCP サーバー登録を IaC 化できるか ❌ OAuth 3LO は CloudFormation / CDK 非対応(apiKey / oAuthClientCredentials のみ)
5 ツール許可リストを IaC 化できるか AWS::DevOpsAgent::Association で可能。Tools は差分デプロイで変更できる
6 MCP 経由で PR を作れるか create_branchpush_filescreate_pull_request で完走
7 create_or_update_file は使えるか ⚠️ base64 でファイル全体を渡す仕様。引数が途中で切れ、日本語も壊れた

片付けについて

検証が終わったら、以下を消しておくのが良さそうです。

  • エージェントが作ったプルリクエストとブランチ
  • 検証用スタック(npx cdk destroy DevOpsAgentPrVerification
  • GitHub MCP サーバーのアカウントレベル登録(Association を外してから 機能プロバイダー → アクション → 登録解除
  • GitHub App(インストールを削除し、App 自体も削除)

特に GitHub App は Contents: Read and write を持ったまま残るので、使わないなら消しておくべきです。App のインストールを消せば、MCP サーバー側にトークンが残っていても書き込みはできなくなります。

おわりに

「DevOps Agent は調査だけでなく修正プルリクエストまで作れるのか」を確かめてみました。答えは 「作れるが、ネイティブの GitHub 連携だけでは無理で、GitHub MCP サーバーの接続が必要」 でした。

ネイティブ連携のアクセスレベルが「読み取りと書き込み」と表示されていても、調査チャットに渡るツールは読み取り専用です。ここは表示から素直に推測できず、実際にエージェントにツール一覧を聞いてみるまで分かりませんでした。

最初は「連携を設定したのが古いせいかもしれない」と疑ったのですが、GitHub App の権限は最新で保留中の更新もなく、これは仕様でした。AWS の機能ページを読み直すと、DevOps Agent は修正の指示(agent-ready instructions)までを担当し、実装は Kiro のような別のエージェントに渡す設計になっています。今回やったのは、その「別のエージェント」の役割を GitHub MCP サーバーで肩代わりさせることだったと言えます。

権限設計の観点では、GitHub App + OAuth 3LO は良い落としどころだと思います。長期の PAT を持たずに済み、GitHub App の permissions とインストール先リポジトリで二重に絞れて、GitHub 側にもアプリ名が残ります。その代わり Service の登録は IaC 化できないので、「Service 登録はコンソールで一度だけ、ツール許可リストは CDK で管理」 という分担になります。

ツール許可リストの選定は思ったより効きました。47 ツールのうち 4 つに絞ることで merge_pull_requestdelete_file を最初から遮断できます。エージェントに書き込み権限を渡すときは、ここを最小にしておくのが効果的だと感じました。

以上

この記事をシェアする

関連記事