/** * サーバーセットアップレシピ本体(`body` = Ansible タスク列 YAML)の静的検証ガード。 * * **セキュリティ上重要**: このロジックは実行環境(agentホスト / 当社 ECS)への攻撃経路 * (任意コマンド実行・他ホストへの委譲・秘密情報の平文ログ出力・危険な * lookup/queryプラグイン経由のファイル読み取り等)を塞ぐための唯一の防御線。 * allowlist に無いモジュール・危険なタスクキーは一律拒否し、フォールバックは * 行わない(CLAUDE.md フォールバック禁止ルール)。 * * ## 経路別モード(`mode`) * - `ecs`: 当社基盤(ECS oneshot)で実行。厳格 allowlist を維持する。 * - `resident`: 顧客の閉域ネットワーク内の常駐エージェントで実行。モジュール allowlist を * 寛容化する(追加モジュールを許可)。**ただし** denylist(危険タスクキー)・lookup 拒否・ * copy/template の src 拒否・`ansible_*`/magic 変数拒否は両モードで維持する。 * * API 保存時(レシピ作成/更新)は安全側に倒し `mode: 'ecs'`(厳格側)で検証してよい * (早期 UX フィードバック)。権威判定は agent 実行時に `dispatchMode` に応じたモードで行う。 * * ## `include_role` スニペット(組み込みステップ) * 組み込みステップ(os_init/ssh_key/docker/nvm/claude_cli/codex/ai_support_agent/ * ai_support_agent_k8s/web_server/database/dns_tls/gitlab_runner/github_runner/ * gitlab_runner_k8s/github_runner_k8s/k3s/ * tailscale)は、bundled role を呼ぶ * `include_role` タスクとして表現する。`include_role` は下記 allowlist のロールのみ * 許可し、role 名と * 許可 param キーを専用バリデータで個別検査する。ロール変数は **task レベルの `vars:`** * (`include_role:` と同じインデントの兄弟キー)で渡す。`ansible.builtin.include_role` * モジュールに `vars` というパラメータは存在しない(モジュール引数内にネストすると実機の * `ansible-playbook` が `Invalid options for ansible.builtin.include_role: vars` で拒否する * ため、そちらは許可しない)。include_role タスクに限り task レベルの `vars` を * `FORBIDDEN_TASK_KEYS` の対象から除外し、中身は他タスクの `vars`(禁止のまま)と同じ * 予約語・マジック変数名チェックを適用する。 * * 設計: admin-docs/docs/specifications/git-artifact-platform.md */ export type AnsibleTaskRouteMode = 'resident' | 'ecs'; export interface ValidateAnsibleTasksOptions { /** 実行経路。`ecs`=厳格、`resident`=モジュール allowlist 寛容化。 */ mode: AnsibleTaskRouteMode; /** * この検証呼び出し時点で「secretとして扱うべき」変数名の集合 * (api保存時は空集合でよい。no_log付与はagent実行時に行う)。 */ secretVarNames?: ReadonlySet; } export interface AnsibleTaskViolation { taskIndex: number; key: string; reason: string; } export interface AnsibleTaskValidationResult { ok: boolean; violations: AnsibleTaskViolation[]; normalizedTasks?: Record[]; } /** * `include_role` で呼び出しを許可する bundled role の集合。 * 組み込みステップ(スニペット)に 1:1 対応し、`ansible/roles/` 配下の実ディレクトリと * 1:1 で一致すること(追加漏れ・非対称は spec で検出する)。 * * `claude_cli`/`codex`/`ai_support_agent` は `nvm` ロールで導入した Node.js/npm に * 依存する。`gitlab_runner`/`github_runner`(CI ランナー登録)で executor=docker を * 使う場合は `docker` ロールに依存する。ロール間の自動依存機構は無いため、レシピ * 作成者が依存ロールを先に include する運用とし、各ロールは前提を `assert` で検証する。 * * `k3s` は単一ロールで OS 前提整備・ephemeral ディスク・k3s(HA/単一)・gVisor を * トグル変数で制御する重量ロール。破壊的なディスク操作・秘匿トークンを扱うため、 * ロール内部で by-id/UUID 強制・冪等ガード・no_log を徹底する(roles/k3s 参照)。 * * `tailscale` は Tailscale(WireGuard メッシュVPN)へ auth key で非対話参加する単一 * ロール。秘匿の auth key を 0600 一時ファイル+`--auth-key=file:` で扱い argv に * 載せない(roles/tailscale 参照)。 * * `ai_support_agent_k8s` は kubectl/kubeconfig を持つノード上で動き、エージェントを * StatefulSet としてクラスタへ配置する。ホスト常駐の `ai_support_agent` とは配送経路が * 異なり、対象ホストに Node.js を導入しないため `nvm` には依存しない。エージェント * トークンは 0600 一時ファイル経由で `kubectl create secret --from-file=` に渡し、argv・ * `environment:`・生成マニフェストのいずれにも載せない(roles/ai_support_agent_k8s 参照)。 * * `gitlab_runner_k8s`/`github_runner_k8s` は CI ランナーを**ホストではなくクラスタ上**へ * 配置する。`ai_support_agent_k8s` と同じく kubectl/kubeconfig を持つノードで動き、 * トークン Secret を 0600 一時ファイル経由で作ったうえで、HelmChart CR には * 「既存 Secret の名前」だけを書く(秘匿値は生成マニフェストに載らない)。チャートの * 取得元(repo / OCI 参照 / チャート名)はロール内のインラインリテラルであり、レシピ側の * task-level vars から差し替えできない。ジョブは非特権に固定し、privileged / dind を * 有効化する変数は提供しない(roles/gitlab_runner_k8s・roles/github_runner_k8s 参照)。 */ export declare const INCLUDE_ROLE_ALLOWED_ROLES: ReadonlySet; /** `shared_file` ロールで配布元を指定する変数名。 */ export declare const SHARED_FILE_SRC_VAR = "shared_file_src"; /** * `shared_file_src` に指定できる共有ファイルの相対パス。 * * - Jinja テンプレート(`{{ }}` / `{% %}`)を含まないこと * - 相対パスであること(先頭 `/` を許さない) * - `..` セグメントを含まないこと * * テンプレートを拒む理由は権限ではなく**決定可能性**である。エージェントは playbook を * 走らせる前に body を静的に走査し、取り寄せる共有ファイルを決めてステージングする。 * 値が実行時にしか定まらないと、何を取り寄せればよいか分からない。 * * `..` と絶対パスを拒むのは、ロールが `src` をステージングディレクトリからの相対パスとして * 組み立てるためである。ここを抜けると、エージェント上の任意ファイル(自身のトークンや * SSH 秘密鍵)を対象サーバーへ配布できてしまう。`ansible.builtin.copy` の `src` を * 本体タスクで禁止しているのと同じ理由の防御であり、この検証がその代替になっている。 */ export declare function isValidSharedFileSrc(value: unknown): value is string; /** * サーバーセットアップレシピ本体(Ansible タスク列 YAML)を検証する。 * * @param body テナントadminが入力したタスク YAML(トップレベルはタスクの配列) * @param opts.mode 実行経路(`ecs`=厳格 / `resident`=寛容) * @param opts.secretVarNames secretとして扱う変数名(no_log 付与判定用。api保存時は空でよい) */ export declare function validateAnsibleTasks(body: string, opts: ValidateAnsibleTasksOptions): AnsibleTaskValidationResult; //# sourceMappingURL=ansible-task-guard.d.ts.map