第10章:組織管理とチーム運用
10.1 AI協働を前提としたOrganization設計
Organizationの作成手順
基本情報の設定
- GitHub.comで「+」→「New organization」
- プランの選択(Free/Team/Enterprise)
- 組織情報の入力
organization_settings:
name: "ai-research-lab"
display_name: "AI Research Laboratory"
email: "admin@ai-research-lab.org"
description: "AI-Collaborative research and development team using CLEAR framework"
url: "https://ai-research-lab.org"
location: "Tokyo, Japan"
billing_email: "billing@ai-research-lab.org"
# AI協働設定(Copilot Business/Enterprise)
copilot_settings:
enabled: true
plan: "business" # business or enterprise
# 本書で提唱するAI協働フレームワークを適用
ai_collaboration_policy:
framework: "CLEAR" # 第2章で定義したフレームワーク
framework_description: "Context-Learning-Explanation-Assessment-Reflection"
templates_required: true
metrics_tracking: enabled
chapter2_integration: true # 第2章のテンプレートとプロセスを使用
AI協働に最適化されたセキュリティ設定
security_settings:
# 二要素認証
two_factor_authentication:
required: true
grace_period_days: 7
# ベース権限
base_permissions: "read" # none, read, write, admin
# AI協働権限
ai_collaboration:
copilot_access: "managed" # none, all, managed
require_ai_disclosure: true
ai_code_review_mandatory: true
# リポジトリ作成権限
members_can_create_repositories:
public: false
private: true
internal: true # Enterprise only
ai_template_required: true # AI協働テンプレート必須
# フォーク権限
members_can_fork_private_repositories: false
# Pages設定
members_can_create_pages:
public: false
private: true
# AIメトリクス
ai_metrics:
track_usage: true
weekly_reports: true
share_best_practices: true
組織プロファイルの設定
READMEの作成
.github/profile/README.md
:
# AI Research Laboratory
## 🚀 Our Mission
最先端のAI技術を研究開発し、社会に貢献する
## 🔬 Research Areas
- Computer Vision
- Natural Language Processing
- Reinforcement Learning
- MLOps & AI Infrastructure
## 📊 Key Projects
| Project | Description | Status |
|---------|-------------|--------|
| [vision-transformer](link) | Vision Transformer implementation | Active |
| [nlp-toolkit](link) | NLP preprocessing tools | Stable |
| [rl-framework](link) | Reinforcement learning framework | Beta |
## 👥 Teams
- **Research Team**: 基礎研究
- **Engineering Team**: 実装・最適化
- **MLOps Team**: インフラ・デプロイ
## 📚 Publications
- [Paper 1](link) - CVPR 2024
- [Paper 2](link) - NeurIPS 2023
## 🤝 Contributing
See our [Contributing Guide](CONTRIBUTING.md)
## 📬 Contact
- Email: contact@ai-research-lab.org
- Discord: [Join our server](discord-link)
組織の可視性設定
メンバーの公開設定
# org_visibility.py
class OrganizationVisibility:
def __init__(self, org_name, token):
self.github = Github(token)
self.org = self.github.get_organization(org_name)
def set_member_visibility(self, username, visibility='public'):
"""
メンバーの可視性を設定
visibility: 'public' or 'private'
"""
member = self.org.get_member(username)
if visibility == 'public':
self.org.publicize_membership(member)
else:
self.org.conceal_membership(member)
def enforce_visibility_policy(self, policy='public'):
"""組織全体の可視性ポリシーを適用"""
for member in self.org.get_members():
try:
if policy == 'public':
self.org.publicize_membership(member)
elif policy == 'private':
self.org.conceal_membership(member)
elif policy == 'optional':
# デフォルトはプライベート、個人で選択可能
pass
except Exception as e:
print(f"Failed to set visibility for {member.login}: {e}")
10.2 AI協働チームの構造設計
チーム階層の設計
AI協働を考慮した階層的チーム構造
team_hierarchy:
engineering:
description: "All engineering teams with AI collaboration"
privacy: "closed" # secret or closed
ai_settings:
copilot_enabled: true
ai_metrics_required: true
sub_teams:
backend:
description: "Backend development"
maintainers: ["backend-lead"]
members: ["dev1", "dev2", "dev3"]
ai_collaboration:
primary_tools: ["GitHub Copilot", "ChatGPT"]
code_review_ai: mandatory
frontend:
description: "Frontend development"
maintainers: ["frontend-lead"]
members: ["dev4", "dev5"]
ai_collaboration:
primary_tools: ["GitHub Copilot", "Figma AI"]
design_ai_integration: true
ml_engineering:
description: "ML Engineering with AI pair programming"
maintainers: ["ml-lead"]
members: ["ml-eng1", "ml-eng2", "ml-eng3"]
ai_collaboration:
primary_tools: ["GitHub Copilot", "Claude", "ChatGPT"]
experiment_tracking: "with AI annotations"
model_development: "AI-assisted"
sub_teams:
computer_vision:
description: "CV team - AI-collaborative development"
members: ["cv-eng1", "cv-eng2"]
ai_specialization: "image generation and analysis"
nlp:
description: "NLP team - AI language model integration"
members: ["nlp-eng1", "nlp-eng2"]
ai_specialization: "prompt engineering and LLM fine-tuning"
ai_collaboration_team:
description: "AI collaboration best practices and tooling"
maintainers: ["ai-collab-lead"]
members: ["ai-specialist1", "ai-specialist2"]
responsibilities:
- "第2章のフレームワーク維持・改善"
- "AI協働メトリクスの分析"
- "チーム向けトレーニング"
- "ベストプラクティスの共有"
チームの作成と管理
プログラムによるチーム管理
# team_manager.py
class TeamManager:
def __init__(self, org_name, token):
self.github = Github(token)
self.org = self.github.get_organization(org_name)
def create_team_hierarchy(self, hierarchy_config):
"""階層的なチーム構造を作成"""
def create_team_recursive(config, parent=None):
# チームを作成
team = self.org.create_team(
name=config['name'],
description=config.get('description', ''),
privacy=config.get('privacy', 'closed'),
parent_team_id=parent.id if parent else None
)
# メンテナーを追加
for maintainer in config.get('maintainers', []):
team.add_membership(
self.github.get_user(maintainer),
role='maintainer'
)
# メンバーを追加
for member in config.get('members', []):
team.add_membership(
self.github.get_user(member),
role='member'
)
# サブチームを作成
for sub_config in config.get('sub_teams', []):
create_team_recursive(sub_config, team)
return team
# ルートチームから作成開始
create_team_recursive(hierarchy_config)
def sync_team_with_ldap(self, team_name, ldap_group):
"""LDAPグループとチームを同期"""
team = self.org.get_team_by_slug(team_name)
# LDAP/SAML同期の設定(Enterprise only)
team.create_or_update_ldap_mapping(
ldap_dn=f"cn={ldap_group},ou=groups,dc=company,dc=com"
)
チーム権限の管理
リポジトリへのチーム権限付与
def grant_team_permissions(self, team_name, repo_patterns, permission='write'):
"""
チームに複数リポジトリへの権限を付与
Args:
team_name: チーム名
repo_patterns: リポジトリパターンのリスト
permission: 'read', 'write', 'admin'
"""
team = self.org.get_team_by_slug(team_name)
for repo in self.org.get_repos():
for pattern in repo_patterns:
if self._match_pattern(repo.name, pattern):
team.add_to_repos(repo)
team.set_repo_permission(repo, permission)
print(f"Granted {permission} to {team_name} for {repo.name}")
def _match_pattern(self, name, pattern):
"""ワイルドカードパターンマッチング"""
import fnmatch
return fnmatch.fnmatch(name, pattern)
# 使用例
manager.grant_team_permissions(
'ml_engineering',
['ml-*', 'model-*', 'training-*'],
'write'
)
9.3 Outside Collaboratorの管理
外部協力者のポリシー
アクセス管理フレームワーク
outside_collaborator_policy:
# 承認プロセス
approval:
required_approvers: 2
approver_teams: ["security", "management"]
# アクセス期限
access_duration:
default_days: 90
max_days: 365
warning_days: 14
# 権限制限
permission_limits:
max_permission: "write" # adminは付与不可
allowed_repos_pattern:
- "public-*"
- "collaboration-*"
forbidden_repos:
- "*-internal"
- "*-private"
- "infrastructure-*"
# 監査要件
audit:
review_interval_days: 30
activity_tracking: true
require_2fa: true
外部協力者の自動管理
期限管理システム
# collaborator_manager.py
from datetime import datetime, timedelta
import json
class CollaboratorManager:
def __init__(self, org_name, token):
self.github = Github(token)
self.org = self.github.get_organization(org_name)
self.metadata_file = "collaborator_metadata.json"
def add_outside_collaborator(self, username, repo_name,
permission='read', days=90,
reason="", approvers=[]):
"""外部協力者を追加(メタデータ付き)"""
repo = self.org.get_repo(repo_name)
# GitHubに追加
repo.add_to_collaborators(username, permission)
# メタデータを保存
metadata = self.load_metadata()
metadata[username] = {
'repos': {
repo_name: {
'permission': permission,
'added_date': datetime.now().isoformat(),
'expiry_date': (datetime.now() + timedelta(days=days)).isoformat(),
'reason': reason,
'approvers': approvers
}
}
}
self.save_metadata(metadata)
# 通知
self.notify_addition(username, repo_name, days)
def check_expirations(self):
"""期限切れの協力者をチェック"""
metadata = self.load_metadata()
expired = []
warning = []
for username, user_data in metadata.items():
for repo_name, repo_data in user_data['repos'].items():
expiry = datetime.fromisoformat(repo_data['expiry_date'])
days_until_expiry = (expiry - datetime.now()).days
if days_until_expiry <= 0:
expired.append({
'username': username,
'repo': repo_name,
'expired_days': abs(days_until_expiry)
})
elif days_until_expiry <= 14:
warning.append({
'username': username,
'repo': repo_name,
'days_remaining': days_until_expiry
})
return {'expired': expired, 'warning': warning}
def remove_expired_collaborators(self, dry_run=True):
"""期限切れの協力者を削除"""
check_result = self.check_expirations()
for item in check_result['expired']:
if not dry_run:
repo = self.org.get_repo(item['repo'])
repo.remove_from_collaborators(item['username'])
# メタデータを更新
metadata = self.load_metadata()
del metadata[item['username']]['repos'][item['repo']]
if not metadata[item['username']]['repos']:
del metadata[item['username']]
self.save_metadata(metadata)
print(f"{'[DRY RUN] ' if dry_run else ''}Removed {item['username']} from {item['repo']}")
def generate_access_report(self):
"""外部協力者のアクセスレポート生成"""
report = {
'generated_at': datetime.now().isoformat(),
'total_collaborators': 0,
'by_permission': {'read': 0, 'write': 0, 'admin': 0},
'by_repo': {},
'expiring_soon': [],
'inactive_users': []
}
# 全リポジトリを確認
for repo in self.org.get_repos():
collaborators = []
for collab in repo.get_collaborators(affiliation='outside'):
permission = repo.get_collaborator_permission(collab)
collaborators.append({
'username': collab.login,
'permission': permission,
'last_active': self.get_last_activity(collab, repo)
})
report['by_permission'][permission] += 1
# 非アクティブユーザー
if self.get_last_activity(collab, repo) > 30:
report['inactive_users'].append({
'username': collab.login,
'repo': repo.name,
'days_inactive': self.get_last_activity(collab, repo)
})
if collaborators:
report['by_repo'][repo.name] = collaborators
report['total_collaborators'] += len(collaborators)
return report
9.4 SAML SSOとの連携
SAML SSO設定(Enterprise)
基本設定
saml_configuration:
# Identity Provider設定
idp:
entity_id: "https://idp.company.com"
sso_url: "https://idp.company.com/sso"
certificate: |
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
...
-----END CERTIFICATE-----
# 属性マッピング
attribute_mapping:
name_id: "email"
email: "email"
name: "displayName"
username: "sAMAccountName"
groups: "memberOf"
# グループ同期
group_sync:
enabled: true
base_dn: "ou=github,ou=groups,dc=company,dc=com"
filter: "(objectClass=group)"
# セッション設定
session:
timeout_hours: 8
require_reauthentication: true
SCIM プロビジョニング
自動ユーザー管理
# scim_sync.py
class SCIMSync:
def __init__(self, org_name, scim_token):
self.org_name = org_name
self.scim_endpoint = f"https://api.github.com/scim/v2/organizations/{org_name}"
self.headers = {
'Authorization': f'Bearer {scim_token}',
'Content-Type': 'application/scim+json'
}
def create_user(self, user_data):
"""SCIMでユーザーを作成"""
scim_user = {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": user_data['username'],
"name": {
"givenName": user_data['first_name'],
"familyName": user_data['last_name']
},
"emails": [{
"value": user_data['email'],
"primary": True
}],
"externalId": user_data['employee_id'],
"active": True
}
response = requests.post(
f"{self.scim_endpoint}/Users",
json=scim_user,
headers=self.headers
)
return response.json()
def sync_groups(self, group_mappings):
"""ADグループとGitHubチームを同期"""
for ad_group, github_team in group_mappings.items():
ad_members = self.get_ad_group_members(ad_group)
# GitHubチームを作成/更新
team_data = {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": github_team,
"members": [
{"value": member['id']} for member in ad_members
]
}
# 既存チームを検索
existing_team = self.find_team(github_team)
if existing_team:
# 更新
requests.put(
f"{self.scim_endpoint}/Groups/{existing_team['id']}",
json=team_data,
headers=self.headers
)
else:
# 作成
requests.post(
f"{self.scim_endpoint}/Groups",
json=team_data,
headers=self.headers
)
9.5 監査ログの活用
監査ログの収集と分析
ログ収集設定
# audit_log_collector.py
class AuditLogCollector:
def __init__(self, org_name, token):
self.org_name = org_name
self.headers = {
'Authorization': f'token {token}',
'Accept': 'application/vnd.github.v3+json'
}
def fetch_audit_log(self, start_date=None, end_date=None):
"""監査ログを取得"""
url = f"https://api.github.com/orgs/{self.org_name}/audit-log"
params = {}
if start_date:
params['after'] = start_date.isoformat()
if end_date:
params['before'] = end_date.isoformat()
all_events = []
page = 1
while True:
params['page'] = page
response = requests.get(url, headers=self.headers, params=params)
if response.status_code != 200:
break
events = response.json()
if not events:
break
all_events.extend(events)
page += 1
return all_events
def analyze_security_events(self, events):
"""セキュリティ関連イベントを分析"""
security_events = {
'auth_failures': [],
'permission_changes': [],
'repo_visibility_changes': [],
'member_changes': [],
'suspicious_activities': []
}
for event in events:
# 認証失敗
if event['action'] == 'auth.login_failed':
security_events['auth_failures'].append(event)
# 権限変更
elif event['action'] in ['team.add_repository',
'org.update_member_permission']:
security_events['permission_changes'].append(event)
# リポジトリ可視性変更
elif event['action'] == 'repo.change_visibility':
security_events['repo_visibility_changes'].append(event)
# メンバー変更
elif event['action'] in ['org.add_member', 'org.remove_member']:
security_events['member_changes'].append(event)
# 疑わしい活動
if self.is_suspicious(event):
security_events['suspicious_activities'].append(event)
return security_events
def is_suspicious(self, event):
"""疑わしい活動を検出"""
suspicious_patterns = [
# 短時間での大量操作
lambda e: e['action'].startswith('repo.download') and
self.count_recent_downloads(e['actor']) > 10,
# 通常と異なる時間帯のアクセス
lambda e: self.is_unusual_time(e['timestamp']),
# 通常と異なる場所からのアクセス
lambda e: self.is_unusual_location(e.get('actor_location'))
]
return any(pattern(event) for pattern in suspicious_patterns)
def generate_compliance_report(self, start_date, end_date):
"""コンプライアンスレポート生成"""
events = self.fetch_audit_log(start_date, end_date)
report = {
'period': {
'start': start_date.isoformat(),
'end': end_date.isoformat()
},
'summary': {
'total_events': len(events),
'unique_actors': len(set(e['actor'] for e in events)),
'event_types': {}
},
'security_analysis': self.analyze_security_events(events),
'compliance_checks': {
'unauthorized_access_attempts': 0,
'policy_violations': 0,
'data_exports': 0
}
}
# イベントタイプ別集計
for event in events:
action = event['action']
report['summary']['event_types'][action] = \
report['summary']['event_types'].get(action, 0) + 1
return report
リアルタイム監視
Webhook設定
# audit-webhook.yml
webhook_config:
url: "https://security.company.com/github-audit"
secret: "${WEBHOOK_SECRET}"
events:
- organization
- repository
- team
- member
- security_alert
filters:
actions:
- "*.delete"
- "*.create"
- "repo.change_visibility"
- "org.update_member_permission"
まとめ
本章では、GitHub組織管理とチーム運用について学習しました:
- Organizationの作成と適切な初期設定
- 階層的なチーム構造で効率的な権限管理
- 外部協力者の期限付きアクセス管理
- SAML SSOでエンタープライズ認証統合
- 監査ログでセキュリティとコンプライアンス確保
次章では、実践的なセキュリティ設定について学習します。
確認事項
- Organizationの基本設定が完了している
- チーム構造を設計・実装できる
- 外部協力者の管理プロセスを確立している
- SSO連携の仕組みを理解している(Enterprise)
- 監査ログを活用した監視体制がある