# トレースの取得 {#trace-collection}

Takumi Runner は、ワークフロー実行中に発生するプロセス・ネットワーク・ファイル操作を eBPF で網羅的にキャプチャします。このページでは、取得されるイベントの種類、データ形式、および生データへのアクセス方法を説明します。

## 取得の仕組み {#how-it-works}

Takumi Runner のトレース取得は、Linux カーネルの **eBPF**（extended Berkeley Packet Filter）テクノロジーを基盤としています。eBPF を利用することで、ワークフロー内で実行されるユーザーコードに一切の変更を加えることなく、カーネルレイヤで VM 内での動作をキャプチャできます。

## キャプチャされるイベント {#captured-events}

Takumi Runner の eBPF トレーサーは、以下のシステムコールレベルのイベントを記録します。

| イベント種別   | 説明                 | 記録されるフィールド                    |
| -------------- | -------------------- | --------------------------------------- |
| `process_exec` | プロセスの実行       | PID、コマンド名、ファイルパス、引数     |
| `net_connect`  | ネットワーク接続     | PID、接続先アドレス、ポート、プロトコル |
| `dns_query`    | DNS ルックアップ     | PID、ホスト名                           |
| `file_open`    | ファイルのオープン   | PID、パス、フラグ                       |
| `file_write`   | ファイルへの書き込み | PID、パス、書き込みバイト数             |

1 回のジョブ実行で、数千から数万件のイベントが記録されます。

## トレースの用途 {#use-cases}

収集されたトレースは、以下のようなセキュリティ分析に活用できます。

- **サプライチェーン攻撃の検知** として、`npm install` や `pip install` 中に不審な外部ホストへの通信が発生していないかを確認する
- **インシデント調査** として、特定のジョブ実行中に `curl` や `wget` が実行されたか、`~/.netrc` などの認証情報を含むファイルにアクセスがあったかを追跡する
- **ベースライン分析** として、正常なビルドのトレースと異常なビルドのトレースを比較し、差分を特定する

## トレースのデータ形式 {#data-format}

トレースデータは **JSONL（改行区切り JSON）** 形式で保存されます。1 行が 1 イベントに対応し、各行は独立した JSON オブジェクトです。すべてのイベントには共通フィールドとして `type`（イベント種別）と `timestamp`（発生時刻、ISO 8601 形式）が含まれます。

:::warning
以下に示すフィールド定義は、現時点での実装に基づく参考情報です。フィールドの追加・変更・削除が事前の通知なく行われる場合があります。
:::

### `process_exec` {#process-exec}

プロセスの実行を記録します。

| フィールド | 型       | 説明               |
| ---------- | -------- | ------------------ |
| `pid`      | number   | プロセス ID        |
| `comm`     | string   | コマンド名         |
| `filename` | string   | 実行ファイルのパス |
| `args`     | string[] | コマンドライン引数 |

```json
{
  "type": "process_exec",
  "timestamp": "2025-01-15T10:30:01Z",
  "pid": 1234,
  "comm": "npm",
  "filename": "/usr/bin/npm",
  "args": ["npm", "install"]
}
```

### `net_connect` {#net-connect}

ネットワーク接続を記録します。

| フィールド | 型     | 説明                        |
| ---------- | ------ | --------------------------- |
| `pid`      | number | プロセス ID                 |
| `dst_addr` | string | 接続先 IP アドレス          |
| `dst_port` | number | 接続先ポート番号            |
| `protocol` | string | プロトコル（`tcp` / `udp`） |

```json
{
  "type": "net_connect",
  "timestamp": "2025-01-15T10:30:02Z",
  "pid": 1235,
  "dst_addr": "104.16.23.35",
  "dst_port": 443,
  "protocol": "tcp"
}
```

### `dns_query` {#dns-query}

DNS ルックアップを記録します。

| フィールド | 型     | 説明                 |
| ---------- | ------ | -------------------- |
| `pid`      | number | プロセス ID          |
| `hostname` | string | 問い合わせたホスト名 |

```json
{
  "type": "dns_query",
  "timestamp": "2025-01-15T10:30:02Z",
  "pid": 1235,
  "hostname": "registry.npmjs.org"
}
```

### `file_open` {#file-open}

ファイルのオープンを記録します。

| フィールド | 型     | 説明                              |
| ---------- | ------ | --------------------------------- |
| `pid`      | number | プロセス ID                       |
| `path`     | string | ファイルパス                      |
| `flags`    | string | オープンフラグ（`O_RDONLY` など） |

```json
{
  "type": "file_open",
  "timestamp": "2025-01-15T10:30:03Z",
  "pid": 1235,
  "path": "/home/runner/work/app/package.json",
  "flags": "O_RDONLY"
}
```

### `file_write` {#file-write}

ファイルへの書き込みを記録します。

| フィールド | 型     | 説明             |
| ---------- | ------ | ---------------- |
| `pid`      | number | プロセス ID      |
| `path`     | string | ファイルパス     |
| `bytes`    | number | 書き込みバイト数 |

```json
{
  "type": "file_write",
  "timestamp": "2025-01-15T10:30:04Z",
  "pid": 1235,
  "path": "/home/runner/work/app/node_modules/.package-lock.json",
  "bytes": 2048
}
```

## トレースの保管期間 {#retention}

トレースデータは、取得日から最低 **90 日間** 保管されます。90 日を経過したトレースデータは削除される場合があります。

サブスクリプションの解約時には、利用規約その他の定めに従ってトレースデータが削除されます。

:::info
保持期間の延長を希望される場合は、アカウント担当までお問い合わせください。ご契約やご利用の状況により、ご要望にお応えできない場合があります。
:::

## 生データへのアクセス {#raw-data-access}

Shisho Cloud コンソールのジョブ詳細画面にある **クエリ** タブでは、トレースデータに対して SQL（DuckDB）を使った自由なクエリを実行できます。

![クエリタブ](/docs/ja/_md-assets/61508f6bc4-job-query.png)

また、各ジョブ実行のトレースデータを JSONL ファイルとしてダウンロードすることもできます。ダウンロードした生データは、独自のスクリプトやツールで自由に分析できます。

:::info
生データは gzip 圧縮された JSONL 形式です。`gunzip` で展開してから `jq` 等で処理できます。

```bash
gunzip trace.jsonl.gz
cat trace.jsonl | jq 'select(.type == "net_connect")'
```

:::

## クエリ例 {#example-queries}

以下のクエリはジョブ詳細画面の **クエリ** タブにそのままコピー＆ペーストして実行できます。トレースデータはすべて単一の `events` テーブルに格納されており、イベント種別や各フィールドへは `json_extract_string(data, '$.type')` のように `$.<フィールド名>` で参照します。

### Runner.Worker プロセスメモリの読み取り検出 {#example-runner-worker-memory}

GitHub Actions の `Runner.Worker` プロセスは、ジョブで利用する秘密情報（`secrets.*` や `${{ ... }}` で展開される値など）を自身のアドレス空間上に保持しています。GitHub Actions を狙ったサプライチェーン攻撃 — 特に 2025 年 3 月の `tj-actions/changed-files` 事案 — では、同じジョブ内で実行される悪意あるアクションが `/proc/<Runner.Worker の pid>/mem` や `/proc/<Runner.Worker の pid>/maps` を読み取ることでシークレットを窃取していました。正常なワークフロー実行では Runner.Worker の PID に対して `/proc/<pid>/mem` や `/proc/<pid>/maps` へアクセスするプロセスは基本的に存在しないため、このクエリにヒットがあればシークレット窃取の強い兆候と判断できます。

以下のクエリは、まず `process_exec` イベントから Runner.Worker の PID を取得し、その PID に対して `/proc/<pid>/mem` または `/proc/<pid>/maps` にアクセスしたイベントをすべて返します。`/proc/self/maps` はプロセスが自分自身のメモリマップを読み取る正当な用途（ランタイムによる自己イントロスペクションなど）で頻繁に参照されるため、明示的に除外しています。

```sql
WITH runner_pid AS (
  SELECT json_extract_string(data, '$.pid') AS pid
  FROM events
  WHERE json_extract_string(data, '$.type') == 'process_exec'
    AND json_extract_string(data, '$.filename') LIKE '%Runner.Worker%'
)
SELECT * FROM events
WHERE json_extract_string(data, '$.path') = concat('/proc/', (SELECT pid FROM runner_pid) ,'/mem')
  OR (
    json_extract_string(data, '$.path') = concat('/proc/', (SELECT pid FROM runner_pid) ,'/maps')
    AND json_extract_string(data, '$.path') != '/proc/self/maps'
  )
```
