Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/ghas.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# GHAS / Actions セキュリティ設定(declarative policy)
#
# engine: ghas-setup がこのファイルを読んで `gh api` に適用する。
# ポリシー値(どの scanner を有効にするか・enforcement・Actions 権限)はすべてここに集約し、
# engine 側はロジックだけを持つ。git diff だけでポリシー変更意図が追えるようにインラインで文書化する。
# 各項目の意味は https://docs.github.com/en/rest/code-security/configurations を参照。
#
# これは devtools 自身の dogfood config 兼・利用側がコピーする書式例。利用側は org を自分の org に変える。

org: airs

configuration:
name: airs-default
description: airs org default code security configuration. Managed by ghas-setup.
# enforced: repo 側で設定をオーバーライド不可に強制する(org ポリシーを全 repo へ確実に適用)
enforcement: enforced
scanners:
# GHAS 本体。code scanning / secret scanning 等の前提となるため有効化
advanced_security: enabled
# 依存グラフ。Dependabot alerts / security updates の前提
dependency_graph: enabled
# 既知 CVE を含む依存を検知してアラート
dependabot_alerts: enabled
# CVE 修正版への PR を自動生成(サプライチェーン防御の中核)
dependabot_security_updates: enabled
# コミット履歴・push 内のシークレット検知
secret_scanning: enabled
# シークレットを含む push をブロック(漏洩を未然に防ぐ)
secret_scanning_push_protection: enabled
# 検知したシークレットが有効(生きている)かを発行元 API で検証
secret_scanning_validity_checks: enabled
# 既知パターン外の汎用シークレット(独自トークン等)も検知
secret_scanning_non_provider_patterns: enabled
# 脆弱性の非公開報告(private vulnerability reporting)受付を有効化
private_vulnerability_reporting: enabled

# 新規 repo の default configuration に本 configuration を指定(all = public/private 問わず)
default_for_new_repos: all
# 既存 repo 全件に attach(all = org 内すべて)
attach_existing_repos: all

actions:
# GITHUB_TOKEN の既定権限を read に最小化(書き込みは workflow 側で明示 grant)
default_workflow_permissions: read
# workflow から PR レビュー承認を不可に(権限昇格経路を塞ぐ)
can_approve_pull_request_reviews: false
41 changes: 11 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ Nix flake × devbox。言語非依存でツールを PATH へ配布し、`flake.
flake.nix # packages / checks (test・lint) / formatter を公開
devbox.json # 開発環境(Nix の test/lint ツール)と自己 dogfooding
.env.template # env-init 用テンプレートの書式例(本 repo の dogfood でも使用)
.github/ghas.yml # ghas-setup 用ポリシー(本 repo の dogfood 兼・書式例)
pkgs/
env-init/
package.nix # env-init を makeWrapper で wrap する派生
env-init # エンジン本体(単体実行可能な生スクリプト)
tests/ # bats テスト
env-init/ # 各 pkg の構成は pkg 内 README を参照
ghas-setup/
```

各パッケージの内部構成は [ツール](#ツール) の各 README を参照。

## 開発

devbox 経由で開発する。
Expand Down Expand Up @@ -52,31 +53,11 @@ SemVer を上げて release する。CLI 契約を変えない依存更新は **

## ツール

### env-init

現在の git worktree 用に `.env` を生成する汎用エンジン。worktree 番号 N を計算し、リポジトリルートの
`.env.template`(bash として 1 回評価される)から `.env` を書き出す。プロジェクト非依存設計で、実行時依存は
`bash` / `git` / `gawk` / `gnused` + coreutils。

**利用側 repo での使い方**:

1. `devbox.json` の `packages` に flake 参照を足し、init_hook で起動する。

```jsonc
{
"packages": ["github:airs/devtools/<ref>#env-init"],
"shell": { "init_hook": ["[ -f .env ] || env-init"] }
}
```

`<ref>` は次の 2 パターンから選ぶ。

- 低摩擦(メジャー追従): `github:airs/devtools/v1#env-init` — 移動タグ。`devbox update` で最新の 1.x を取得する。
- 厳密 pin: `github:airs/devtools/v1.2.0#env-init` — 不変タグ。版を固定し、利用側 Renovate でメジャー更新を抑止できる。
各ツールの使い方・前提・設定書式は各パッケージの README を参照。

本リポジトリ自身の `devbox.json` は、ローカル flake を dogfood するため `path:.#env-init` を使う点だけが利用側と
異なる。Nix を使わない環境では `pkgs/env-init/env-init` を直接実行できる(生スクリプトは単体実行可能なまま)
- [env-init](pkgs/env-init/README.md) — 現在の git worktree 用に `.env` を生成する汎用エンジン。
- [ghas-setup](pkgs/ghas-setup/README.md) — GitHub org の GHAS / セキュリティ設定を `gh api` で一括適用する汎用エンジン

2. **利用側 repo がルートに `.env.template` を用意する**(中央には持ち込まない repo 固有ファイル)。各 worktree で
`N` を参照し、ポートを `$((BASE + N))` でずらし、secret を `openssl rand` / `op read` 等で書く。書式は本リポジトリ
ルートの [`.env.template`](.env.template) を参照(コピー用ではなく書式例)。
利用側は `devbox.json` の `packages` に flake 参照(`github:airs/devtools/<ref>#<tool>`)を足す。`<ref>` の選び方は
[バージョニング](#バージョニング)を参照。本リポジトリ自身は dogfood のため `path:.#<tool>` を使う。Nix を使わない環境では
`pkgs/<tool>/<tool>` を直接実行できる(生スクリプトは単体実行可能なまま)。
5 changes: 4 additions & 1 deletion devbox.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
"deadnix@1",
"nixfmt@1",
"bats@1",
"path:.#env-init"
"gh@2",
"yq-go@4",
"path:.#env-init",
"path:.#ghas-setup"
],
"env": {
"NIX_CONFIG": "experimental-features = nix-command flakes"
Expand Down
33 changes: 31 additions & 2 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# 複数ツールが入るため default は設けない。利用側は常に `#<tool>` を明示する。
packages = forAllSystems (pkgs: {
env-init = pkgs.callPackage ./pkgs/env-init/package.nix { };
ghas-setup = pkgs.callPackage ./pkgs/ghas-setup/package.nix { };
});

# test / lint の単一ソース。`nix flake check` で全て走る。
Expand All @@ -31,9 +32,10 @@
{
# パッケージ build が通ること。
env-init = self.packages.${system}.env-init;
ghas-setup = self.packages.${system}.ghas-setup;

shellcheck = pkgs.runCommand "shellcheck" { nativeBuildInputs = [ pkgs.shellcheck ]; } ''
shellcheck ${./pkgs/env-init/env-init}
shellcheck ${./pkgs/env-init/env-init} ${./pkgs/ghas-setup/ghas-setup}
touch "$out"
'';

Expand All @@ -58,6 +60,33 @@
touch "$out"
'';

# ghas-setup の bats。引数パース・pre-flight・--dry-run は wrap 済みパッケージ
# ($GHAS_SETUP) で、実適用パス(create/update 分岐・API 呼び出し列)は gh をスタブして
# 生スクリプト ($GHAS_SETUP_RAW) を bash で直起動して検証する(wrapper は gh を PATH
# 先頭に prefix するため stub で上書きできない。bash 直起動なら shebang も回避でき、
# PATH 上の stub gh が使われる)。wrap 済みパッケージの closure には gh が入るが、
# --dry-run テストでは gh auth チェックより手前で exit するため起動はしない。
ghas-setup-bats =
pkgs.runCommand "ghas-setup-bats"
{
nativeBuildInputs = [
pkgs.bats
pkgs.bash
pkgs.git
pkgs.coreutils
pkgs.gnugrep
pkgs.yq-go
self.packages.${system}.ghas-setup
];
}
''
cp -r ${./pkgs/ghas-setup/tests} tests
export GHAS_SETUP_RAW=${./pkgs/ghas-setup/ghas-setup}
export HOME="$TMPDIR"
bats tests
touch "$out"
'';

statix = pkgs.runCommand "statix-check" { nativeBuildInputs = [ pkgs.statix ]; } ''
statix check ${./.}
touch "$out"
Expand All @@ -69,7 +98,7 @@
'';

nixfmt = pkgs.runCommand "nixfmt-check" { nativeBuildInputs = [ pkgs.nixfmt ]; } ''
nixfmt --check ${./flake.nix} ${./pkgs/env-init/package.nix}
nixfmt --check ${./flake.nix} ${./pkgs/env-init/package.nix} ${./pkgs/ghas-setup/package.nix}
touch "$out"
'';
}
Expand Down
33 changes: 33 additions & 0 deletions pkgs/env-init/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# env-init

現在の git worktree 用に `.env` を生成する汎用エンジン。worktree 番号 N を計算し、リポジトリルートの
`.env.template`(bash として 1 回評価される)から `.env` を書き出す。プロジェクト非依存設計で、実行時依存は
`bash` / `git` / `gawk` / `gnused` + coreutils。

## 構成

```
package.nix # env-init を makeWrapper で wrap する派生
env-init # エンジン本体(単体実行可能な生スクリプト)
tests/ # bats テスト
```

## 利用側 repo での使い方

1. `devbox.json` の `packages` に flake 参照を足し、init_hook で起動する。

```jsonc
{
"packages": ["github:airs/devtools/<ref>#env-init"],
"shell": { "init_hook": ["[ -f .env ] || env-init"] }
}
```

`<ref>` の選び方(メジャー追従/厳密 pin)はルート [README の「バージョニング」](../../README.md#バージョニング) を参照。

本リポジトリ自身の `devbox.json` は、ローカル flake を dogfood するため `path:.#env-init` を使う点だけが利用側と
異なる。Nix を使わない環境では `pkgs/env-init/env-init` を直接実行できる(生スクリプトは単体実行可能なまま)。

2. **利用側 repo がルートに `.env.template` を用意する**(中央には持ち込まない repo 固有ファイル)。各 worktree で
`N` を参照し、ポートを `$((BASE + N))` でずらし、secret を `openssl rand` / `op read` 等で書く。書式は本リポジトリ
ルートの [`.env.template`](../../.env.template) を参照(コピー用ではなく書式例)。
62 changes: 62 additions & 0 deletions pkgs/ghas-setup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# ghas-setup

GitHub **org 単位**で GHAS / Actions セキュリティ設定を `gh api`(code-security-configurations)で一括適用する汎用エンジン。
適用対象は repo 単位ではなく org 全体で、`default_for_new_repos` / `attach_existing_repos` により新規・既存 repo の両方へ反映される。
engine(本スクリプト)はロジックだけを持ち、org 名・scanner・enforcement・Actions 権限などのポリシー値はすべて config(`.github/ghas.yml`)由来。

## 構成

```
package.nix # ghas-setup を makeWrapper で wrap する派生
ghas-setup # エンジン本体(単体実行可能な生スクリプト)
tests/ # bats テスト
```

## 前提

- 対象 org で **GitHub Advanced Security (GHAS) が有効**であること。GHAS が有効でないと `advanced_security` 等の scanner 適用が失敗する。
- gh CLI が認証済みで **`admin:org` scope** を持つこと(org レベル設定の変更に必要)。

```sh
gh auth login
gh auth refresh -h github.com -s admin:org
```
- `yq`(mikefarah 版 = yq-go)。本パッケージは PATH に同梱する。

## 使い方

1. `devbox.json` の `packages` に flake 参照を足す。

```jsonc
{ "packages": ["github:airs/devtools/<ref>#ghas-setup"] }
```

`<ref>` の選び方(メジャー追従/厳密 pin)はルート [README の「バージョニング」](../../README.md#バージョニング) を参照。

2. **利用側 repo がルートに `.github/ghas.yml` を用意する**(ポリシーの単一ソース。書式は下記)。

3. 適用する。org を変更する前に必ず `--dry-run` で解決値と叩く API を確認する。

```sh
ghas-setup --dry-run # org を変更せず適用予定を表示
ghas-setup # .github/ghas.yml を org へ適用
ghas-setup --config <path> # 別の yaml を渡す(複数 org 用)
```

config は呼び出した git worktree のルートの `.github/ghas.yml`(cwd 基準で解決)。`--config` で上書きできる。

## config(`.github/ghas.yml`)

書式は本リポジトリ実物の [`.github/ghas.yml`](../../.github/ghas.yml) を参照(コピー用の書式例)。利用側はこれをコピーして自 repo の
`.github/ghas.yml` に置き、`org` を自分の org 名に変える。各項目の意味は
[code security configurations の REST API ドキュメント](https://docs.github.com/en/rest/code-security/configurations) を参照。

主な項目:

- `org` — 適用対象の org 名。
- `configuration.name` / `description` / `enforcement` — code security configuration の識別名・説明・強制方法(`enforced` で repo 側のオーバーライドを禁止)。
- `configuration.scanners` — 有効化する scanner(`advanced_security` / `dependency_graph` / `dependabot_alerts` / `secret_scanning` ほか)と値。
- `default_for_new_repos` — 新規 repo の default configuration に指定する範囲(`all` = public/private 問わず)。
- `attach_existing_repos` — 既存 repo へ attach する範囲(`all` = org 内すべて)。
- `actions.default_workflow_permissions` — `GITHUB_TOKEN` の既定権限(`read` で最小化)。
- `actions.can_approve_pull_request_reviews` — workflow から PR レビュー承認を許すか(`false` で権限昇格経路を塞ぐ)。
Loading