diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8b2218e --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +# Terraform and Terragrunt +.terraform/ +.terragrunt-cache/ +*.tfstate +*.tfstate.* +*.tfvars +.terraform.lock.hcl +crash.log +crash.*.log +override.tf +override.tf.json +*_override.tf +*_override.tf.json +.terraformrc +terraform.rc + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Build artifacts +dist/ +build/ +*.log diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bb206ab --- /dev/null +++ b/Makefile @@ -0,0 +1,85 @@ +# Makefile for GitHub Foundations Organizations Layer +# This provides convenient commands for testing, formatting, and validation + +.PHONY: help init test format format-check lint validate security clean all + +help: ## Show this help message + @echo "GitHub Foundations Organizations Layer - Development Commands" + @echo "" + @echo "Usage: make [target]" + @echo "" + @echo "Targets:" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}' + +init: ## Initialize Terraform + @echo "Initializing Terraform..." + cd organizations && terraform init + +test: init ## Run Terraform tests + @echo "Running Terraform tests..." + cd organizations && terraform test -verbose + +format: ## Format Terraform and Terragrunt files + @echo "Formatting Terraform files..." + cd organizations && terraform fmt -recursive + @echo "Formatting Terragrunt files..." + cd organizations && terragrunt hclfmt + +format-check: ## Check if Terraform and Terragrunt files are formatted + @echo "Checking Terraform formatting..." + cd organizations && terraform fmt -check -diff -recursive + @echo "Checking Terragrunt formatting..." + cd organizations && terragrunt hclfmt --terragrunt-check --terragrunt-diff + +validate: init ## Validate Terraform configuration + @echo "Validating Terraform configuration..." + cd organizations && terraform validate + +lint: ## Run TFLint on Terraform files (requires tflint) + @echo "Running TFLint..." + @if command -v tflint >/dev/null 2>&1; then \ + cd organizations && tflint --init && tflint --recursive; \ + else \ + echo "TFLint not installed. Install from: https://github.com/terraform-linters/tflint"; \ + exit 1; \ + fi + +security: ## Run security scan with Trivy (requires trivy) + @echo "Running security scan..." + @if command -v trivy >/dev/null 2>&1; then \ + trivy config organizations/; \ + else \ + echo "Trivy not installed. Install from: https://aquasecurity.github.io/trivy/"; \ + exit 1; \ + fi + +clean: ## Clean Terraform artifacts + @echo "Cleaning Terraform artifacts..." + find organizations -type d -name ".terraform" -exec rm -rf {} + 2>/dev/null || true + find organizations -type d -name ".terragrunt-cache" -exec rm -rf {} + 2>/dev/null || true + find organizations -type f -name ".terraform.lock.hcl" -delete 2>/dev/null || true + +pre-commit-install: ## Install pre-commit hooks + @echo "Installing pre-commit hooks..." + @if command -v pre-commit >/dev/null 2>&1; then \ + pre-commit install; \ + echo "Pre-commit hooks installed successfully!"; \ + else \ + echo "pre-commit not installed. Install with: pip install pre-commit"; \ + exit 1; \ + fi + +pre-commit-run: ## Run pre-commit hooks on all files + @echo "Running pre-commit hooks..." + @if command -v pre-commit >/dev/null 2>&1; then \ + pre-commit run --all-files; \ + else \ + echo "pre-commit not installed. Install with: pip install pre-commit"; \ + exit 1; \ + fi + +all: format validate test ## Run format, validate, and test + +check: format-check validate test ## Run format check, validate, and test (for CI) + +.DEFAULT_GOAL := help diff --git a/organizations/README.md b/organizations/README.md index 408515c..f0fb81d 100644 --- a/organizations/README.md +++ b/organizations/README.md @@ -10,6 +10,7 @@ * [Configuring Repositories](#configuring-repositories) * [Configuring Teams](#configuring-teams) * [Secret Management](#secret-management) + * [Testing](#testing) * [Running the Organizations Layer locally](#running-the-organizations-layer-locally) * [Prerequisites](#prerequisites) * [Pre-installed tools](#pre-installed-tools) @@ -137,6 +138,69 @@ See the documentation [here](./TEAMS_REPOS.md#configuring-teams) See the documentation [here](./SECRETS.md) +## Testing + +The organizations layer includes comprehensive testing capabilities to validate your Terraform and Terragrunt configurations before committing changes. + +### Quick Start + +Run tests with: +```bash +# Using Make (recommended) +make test + +# Or using Terraform directly +cd organizations/ +terraform init +terraform test -verbose +``` + +Check formatting: +```bash +# Using Make (recommended) +make format-check + +# Or manually +terraform fmt -check -recursive +terragrunt hclfmt --terragrunt-check --terragrunt-diff +``` + +Run all checks: +```bash +make check # Runs format-check, validate, and test +``` + +### Pre-commit Hooks + +Install pre-commit hooks to automatically validate changes: +```bash +pip install pre-commit +pre-commit install +``` + +The hooks will automatically run format checks, validation, linting, and security scans before each commit. + +### Documentation + +For detailed testing instructions, see the [Testing Guide](./TESTING.md). + +The testing guide covers: +- Running Terraform native tests +- Format checking for Terraform and Terragrunt +- Pre-commit hook setup and usage +- Validation and security scanning +- Example configurations +- Troubleshooting common issues + +### Example Configurations + +The organizations layer includes example configurations to help you get started: +- **Organization settings**: `organizations/example-org/terragrunt.hcl` +- **Project structure**: `projects/example-project/example-org/` +- **Provider configuration**: `providers/example-org/providers.hcl` + +These examples demonstrate best practices and can be used as templates for your own configurations. + ## Running the Organizations Layer locally ### Prerequisites diff --git a/organizations/TESTING.md b/organizations/TESTING.md new file mode 100644 index 0000000..006f15a --- /dev/null +++ b/organizations/TESTING.md @@ -0,0 +1,311 @@ +# Testing Guide for Organizations Layer + +This guide explains how to test your Terraform and Terragrunt configurations in the organizations layer before committing changes. + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [Running Tests](#running-tests) +- [Format Checking](#format-checking) +- [Pre-commit Hooks](#pre-commit-hooks) +- [Validation](#validation) +- [Security Scanning](#security-scanning) +- [Example Configurations](#example-configurations) + +## Prerequisites + +Before running tests, ensure you have the following installed: + +- **Terraform** (v1.7.5 or later): [Installation Guide](https://developer.hashicorp.com/terraform/downloads) +- **Terragrunt** (v0.55.18 or later): [Installation Guide](https://terragrunt.gruntwork.io/docs/getting-started/install/) +- **TFLint** (optional but recommended): [Installation Guide](https://github.com/terraform-linters/tflint) +- **pre-commit** (optional but recommended): [Installation Guide](https://pre-commit.com/#install) + +## Running Tests + +### Terraform Native Tests + +The organizations layer includes a comprehensive test file (`main.tftest.hcl`) that validates: +- Organization settings configuration +- Repository configuration +- Team configuration +- Security settings +- Naming conventions +- Email format validation + +#### Using Make (Recommended) + +The easiest way to run tests is using the provided Makefile: + +```bash +# Show all available commands +make help + +# Run all checks (format, validate, test) +make check + +# Run tests only +make test + +# Format code +make format + +# Check formatting without modifying files +make format-check + +# Validate configuration +make validate +``` + +#### Using Terraform Directly + +To run the tests directly with Terraform: + +```bash +cd organizations/ +terraform init +terraform test -verbose +``` + +The test output will show: +- ✅ Passed tests (all assertions successful) +- ❌ Failed tests (with specific error messages) + +### Example Test Output + +``` +main.tftest.hcl... in progress + run "organization_settings_validation"... pass + run "repository_configuration_validation"... pass + run "team_configuration_validation"... pass + run "security_settings_validation"... pass + run "naming_conventions_validation"... pass + run "email_format_validation"... pass +main.tftest.hcl... tearing down +main.tftest.hcl... pass +``` + +## Format Checking + +### Using Make (Recommended) + +```bash +# Check formatting without modifying files +make format-check + +# Automatically format all files +make format +``` + +### Check Terraform Formatting Manually + +Check if your Terraform files are properly formatted: + +```bash +cd organizations/ +terraform fmt -check -diff -recursive +``` + +To automatically format files: + +```bash +terraform fmt -recursive +``` + +### Check Terragrunt Formatting + +Check Terragrunt HCL files: + +```bash +cd organizations/ +terragrunt hclfmt --terragrunt-check --terragrunt-diff +``` + +To automatically format Terragrunt files: + +```bash +terragrunt hclfmt +``` + +## Pre-commit Hooks + +This repository includes pre-commit hooks that automatically run checks before each commit. + +### Setup Pre-commit Hooks + +1. Install pre-commit: + ```bash + pip install pre-commit + # or + brew install pre-commit + ``` + +2. Install the hooks: + ```bash + cd /home/runner/work/github-foundations/github-foundations + pre-commit install + ``` + +3. (Optional) Run hooks manually: + ```bash + pre-commit run --all-files + ``` + +### Included Hooks + +The pre-commit configuration includes: +- **terraform_fmt**: Checks Terraform formatting +- **terragrunt_fmt**: Checks Terragrunt HCL formatting +- **terraform_tflint**: Runs TFLint on Terraform files +- **terraform_validate**: Validates Terraform syntax +- **terraform_trivy**: Security scanning of Terraform code +- **gitleaks**: Detects secrets in code +- **trailing-whitespace**: Removes trailing whitespace +- **end-of-file-fixer**: Ensures files end with a newline +- **check-added-large-files**: Prevents committing large files +- **detect-private-key**: Detects private keys + +## Validation + +### Validate Terraform Configuration + +Validate that your Terraform configuration is syntactically valid: + +```bash +cd organizations/ +terraform init +terraform validate +``` + +### Validate Terragrunt Configuration + +Validate your Terragrunt configuration: + +```bash +cd organizations/ +terragrunt validate-inputs +``` + +## Security Scanning + +### TFLint + +Run TFLint to check for potential issues: + +```bash +cd organizations/ +tflint --init +tflint --recursive +``` + +### Trivy + +Run Trivy for security scanning: + +```bash +cd organizations/ +trivy config . +``` + +## Example Configurations + +The `organizations/` folder includes example configurations to help you get started: + +### Organization Settings +- **Location**: `organizations/example-org/terragrunt.hcl` +- **Purpose**: Example organization-level settings + +### Project Structure +- **Location**: `projects/example-project/example-org/` +- **Purpose**: Example project with repositories and teams + +#### Repositories +- **Location**: `projects/example-project/example-org/repositories/terragrunt.hcl` +- **Includes**: + - Public repository example + - Private repository example + - Application repository with branch protection + +#### Teams +- **Location**: `projects/example-project/example-org/teams/terragrunt.hcl` +- **Includes**: + - Admin team + - Developer team + - Viewer team + - Security team (secret) + +### Provider Configuration +- **Location**: `providers/example-org/providers.hcl` +- **Purpose**: GitHub provider setup with GCP Secret Manager integration + +## Testing Workflow + +Follow this workflow before committing changes: + +1. **Make your changes** to Terraform/Terragrunt files + +2. **Run all checks** using Make: + ```bash + make check + ``` + + Or run steps individually: + + ```bash + # Format your code + make format + + # Validate syntax + make validate + + # Run tests + make test + ``` + +3. **Optional: Run security scans**: + ```bash + make lint # Requires tflint + make security # Requires trivy + ``` + +4. **Commit your changes**: + ```bash + git add . + git commit -m "feat: your commit message" + ``` + + Pre-commit hooks will automatically run and validate your changes. + +## Continuous Integration + +When you push your changes or create a pull request, GitHub Actions will automatically: +- Check Terraform formatting +- Check Terragrunt formatting +- Run Terraform plan +- Validate configurations +- Scan for security issues + +The CI pipeline uses the same tools and configurations as local development, ensuring consistency. + +## Troubleshooting + +### Common Issues + +**Issue**: `terraform test` fails with module not found +- **Solution**: Run `terraform init` first to download required modules + +**Issue**: Pre-commit hooks fail +- **Solution**: Run `pre-commit run --all-files` to see detailed errors + +**Issue**: Format check fails +- **Solution**: Run `terraform fmt -recursive` and `terragrunt hclfmt` to auto-format + +**Issue**: TFLint fails +- **Solution**: Run `tflint --init` to download required plugins + +## Additional Resources + +- [Terraform Testing Documentation](https://developer.hashicorp.com/terraform/language/tests) +- [Terragrunt Documentation](https://terragrunt.gruntwork.io/docs/) +- [TFLint Rules](https://github.com/terraform-linters/tflint/tree/master/docs/rules) +- [Pre-commit Terraform Hooks](https://github.com/antonbabenko/pre-commit-terraform) diff --git a/organizations/main.tftest.hcl b/organizations/main.tftest.hcl new file mode 100644 index 0000000..9f018b1 --- /dev/null +++ b/organizations/main.tftest.hcl @@ -0,0 +1,306 @@ +# Terraform test file for organizations layer +# This file provides comprehensive validation testing for configuration patterns +# Run with: terraform test -verbose +# +# This test file validates: +# - Organization settings best practices +# - Repository configuration standards +# - Team configuration patterns +# - Security settings compliance +# - Naming conventions +# - Input validation + +# Mock all external providers to avoid requiring actual credentials +mock_provider "github" {} +mock_provider "google" {} +mock_provider "google-beta" {} + +# Test variables for organization settings +variables { + # Example organization settings + organization_settings = { + name = "test-org" + billing_email = "billing@example.com" + company = "Test Company" + email = "contact@example.com" + location = "Test Location" + description = "Test organization for validation" + has_organization_projects = true + has_repository_projects = true + default_repository_permission = "read" + members_can_create_repositories = false + members_can_create_public_repositories = false + members_can_create_private_repositories = false + members_can_create_pages = false + members_can_fork_private_repositories = false + web_commit_signoff_required = true + advance_security_enabled_for_new_repositories = true + dependabot_alerts_enabled_for_new_repositories = true + dependabot_security_updates_enabled_for_new_repositories = true + dependency_graph_enabled_for_new_repositories = true + secret_scanning_enabled_for_new_repositories = true + secret_scanning_push_protection_enabled_for_new_repositories = true + } + + # Example public repository configuration + public_repositories = { + "test-public-repo" = { + description = "Test public repository" + default_branch = "main" + repository_team_permissions_override = {} + advance_security = false + has_vulnerability_alerts = true + topics = ["test", "public"] + homepage = "https://example.com" + delete_head_on_merge = true + allow_auto_merge = true + dependabot_security_updates = true + } + } + + # Example private repository configuration + private_repositories = { + "test-private-repo" = { + description = "Test private repository" + default_branch = "main" + repository_team_permissions_override = {} + protected_branches = [] + advance_security = false + has_vulnerability_alerts = true + topics = ["test", "private"] + homepage = "" + delete_head_on_merge = true + allow_auto_merge = true + dependabot_security_updates = true + } + } + + # Example team configuration + teams = { + "test-team-admins" = { + name = "Test Admins" + description = "Administrative team for testing" + privacy = "closed" + members = ["admin1", "admin2"] + maintainers = ["admin1"] + } + "test-team-developers" = { + name = "Test Developers" + description = "Developer team for testing" + privacy = "closed" + members = ["dev1", "dev2", "dev3"] + maintainers = ["dev1"] + } + } +} + +# Test 1: Validate organization settings structure +run "organization_settings_validation" { + command = plan + + assert { + condition = output.organization_name == "test-org" + error_message = "Organization name should be 'test-org'" + } + + assert { + condition = output.security_settings.advance_security_enabled == true + error_message = "Advanced security should be enabled" + } + + assert { + condition = output.security_settings.secret_scanning_enabled == true + error_message = "Secret scanning should be enabled" + } + + assert { + condition = output.security_settings.secret_push_protection_enabled == true + error_message = "Secret push protection should be enabled" + } + + assert { + condition = output.security_settings.dependabot_alerts_enabled == true + error_message = "Dependabot alerts should be enabled" + } + + assert { + condition = output.security_settings.dependabot_updates_enabled == true + error_message = "Dependabot security updates should be enabled" + } +} + +# Test 2: Validate repository counts +run "repository_configuration_validation" { + command = plan + + assert { + condition = output.repository_count == 2 + error_message = "Should have 2 repositories configured (1 public + 1 private)" + } + + assert { + condition = output.validation_passed == true + error_message = "All validation checks should pass" + } +} + +# Test 3: Validate team counts +run "team_configuration_validation" { + command = plan + + assert { + condition = output.team_count == 2 + error_message = "Should have 2 teams configured" + } +} + +# Test 4: Test invalid organization name +run "invalid_organization_name" { + command = plan + + variables { + organization_settings = { + name = "Test_Org_Invalid" # Invalid: contains uppercase and underscores + billing_email = "billing@example.com" + default_repository_permission = "read" + web_commit_signoff_required = true + advance_security_enabled_for_new_repositories = true + dependabot_alerts_enabled_for_new_repositories = true + dependabot_security_updates_enabled_for_new_repositories = true + dependency_graph_enabled_for_new_repositories = true + secret_scanning_enabled_for_new_repositories = true + secret_scanning_push_protection_enabled_for_new_repositories = true + } + public_repositories = {} + private_repositories = {} + teams = {} + } + + expect_failures = [ + var.organization_settings, + ] +} + +# Test 5: Test invalid email format +run "invalid_email_format" { + command = plan + + variables { + organization_settings = { + name = "test-org" + billing_email = "invalid-email" # Invalid: not a valid email + default_repository_permission = "read" + web_commit_signoff_required = true + advance_security_enabled_for_new_repositories = true + dependabot_alerts_enabled_for_new_repositories = true + dependabot_security_updates_enabled_for_new_repositories = true + dependency_graph_enabled_for_new_repositories = true + secret_scanning_enabled_for_new_repositories = true + secret_scanning_push_protection_enabled_for_new_repositories = true + } + public_repositories = {} + private_repositories = {} + teams = {} + } + + expect_failures = [ + var.organization_settings, + ] +} + +# Test 6: Test invalid repository permission +run "invalid_repository_permission" { + command = plan + + variables { + organization_settings = { + name = "test-org" + billing_email = "billing@example.com" + default_repository_permission = "super-admin" # Invalid: not a valid permission + web_commit_signoff_required = true + advance_security_enabled_for_new_repositories = true + dependabot_alerts_enabled_for_new_repositories = true + dependabot_security_updates_enabled_for_new_repositories = true + dependency_graph_enabled_for_new_repositories = true + secret_scanning_enabled_for_new_repositories = true + secret_scanning_push_protection_enabled_for_new_repositories = true + } + public_repositories = {} + private_repositories = {} + teams = {} + } + + expect_failures = [ + var.organization_settings, + ] +} + +# Test 7: Test invalid team privacy +run "invalid_team_privacy" { + command = plan + + variables { + organization_settings = { + name = "test-org" + billing_email = "billing@example.com" + default_repository_permission = "read" + web_commit_signoff_required = true + advance_security_enabled_for_new_repositories = true + dependabot_alerts_enabled_for_new_repositories = true + dependabot_security_updates_enabled_for_new_repositories = true + dependency_graph_enabled_for_new_repositories = true + secret_scanning_enabled_for_new_repositories = true + secret_scanning_push_protection_enabled_for_new_repositories = true + } + public_repositories = {} + private_repositories = {} + teams = { + "test-team" = { + name = "Test Team" + description = "Test team" + privacy = "open" # Invalid: must be closed or secret + members = ["user1"] + maintainers = ["user1"] + } + } + } + + expect_failures = [ + var.teams, + ] +} + +# Test 8: Test team without maintainers +run "team_without_maintainers" { + command = plan + + variables { + organization_settings = { + name = "test-org" + billing_email = "billing@example.com" + default_repository_permission = "read" + web_commit_signoff_required = true + advance_security_enabled_for_new_repositories = true + dependabot_alerts_enabled_for_new_repositories = true + dependabot_security_updates_enabled_for_new_repositories = true + dependency_graph_enabled_for_new_repositories = true + secret_scanning_enabled_for_new_repositories = true + secret_scanning_push_protection_enabled_for_new_repositories = true + } + public_repositories = {} + private_repositories = {} + teams = { + "test-team" = { + name = "Test Team" + description = "Test team" + privacy = "closed" + members = ["user1", "user2"] + maintainers = [] # Invalid: must have at least one maintainer + } + } + } + + expect_failures = [ + var.teams, + ] +} diff --git a/organizations/organizations/example-org/terragrunt.hcl b/organizations/organizations/example-org/terragrunt.hcl new file mode 100644 index 0000000..03c708f --- /dev/null +++ b/organizations/organizations/example-org/terragrunt.hcl @@ -0,0 +1,50 @@ +# Example organization settings configuration +# This file demonstrates how to configure organization settings using the organization_settings module +# Copy this file and modify for your own organization + +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "providers" { + path = "${get_repo_root()}/organizations/providers/${basename(get_terragrunt_dir())}/providers.hcl" + expose = true +} + +terraform { + source = "github.com/FociSolutions/github-foundations-modules//modules/organization_settings" +} + +inputs = { + # Organization basic information + name = "example-org" + billing_email = "billing@example.com" + company = "Example Company" + email = "contact@example.com" + location = "Example Location" + description = "Example organization managed by GitHub Foundations" + + # Project settings + has_organization_projects = true + has_repository_projects = true + + # Repository creation permissions + default_repository_permission = "read" + members_can_create_repositories = false + members_can_create_public_repositories = false + members_can_create_private_repositories = false + members_can_create_pages = false + members_can_fork_private_repositories = false + + # Commit signoff requirement + web_commit_signoff_required = true + + # Security settings for new repositories + advance_security_enabled_for_new_repositories = true + dependabot_alerts_enabled_for_new_repositories = true + dependabot_security_updates_enabled_for_new_repositories = true + dependency_graph_enabled_for_new_repositories = true + secret_scanning_enabled_for_new_repositories = true + secret_scanning_push_protection_enabled_for_new_repositories = true +} diff --git a/organizations/projects/example-project/example-org/repositories/terragrunt.hcl b/organizations/projects/example-project/example-org/repositories/terragrunt.hcl new file mode 100644 index 0000000..0807016 --- /dev/null +++ b/organizations/projects/example-project/example-org/repositories/terragrunt.hcl @@ -0,0 +1,109 @@ +# Example repository configuration +# This file demonstrates how to configure repositories for a project using the repository_set module + +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "providers" { + path = "${get_repo_root()}/organizations/providers/${basename(dirname(dirname(get_terragrunt_dir())))}/providers.hcl" + expose = true +} + +terraform { + source = "github.com/FociSolutions/github-foundations-modules//modules/repository_set" +} + +dependency "teams" { + config_path = "../teams" +} + +inputs = { + # Public repositories configuration + public_repositories = { + "example-public-repo" = { + description = "Example public repository" + default_branch = "main" + repository_team_permissions_override = { + # Reference teams from dependency + # "team-slug" = "permission-level" (pull, push, admin, maintain, triage) + } + advance_security = false + has_vulnerability_alerts = true + topics = ["example", "public", "opensource"] + homepage = "https://example.com" + delete_head_on_merge = true + allow_auto_merge = true + dependabot_security_updates = true + + # Template for new repository (optional) + # template = { + # owner = "template-owner" + # repository = "template-repo" + # } + } + } + + # Private repositories configuration + private_repositories = { + "example-private-repo" = { + description = "Example private repository" + default_branch = "main" + repository_team_permissions_override = { + # Example: Give specific teams custom permissions + # "developers" = "push" + # "maintainers" = "admin" + } + protected_branches = [] # Explicitly disable branch protection or configure as needed + advance_security = false + has_vulnerability_alerts = true + topics = ["example", "private", "internal"] + homepage = "" + delete_head_on_merge = true + allow_auto_merge = true + dependabot_security_updates = true + + # Archive settings (optional) + # archived = false + } + + "example-app-repo" = { + description = "Example application repository with advanced features" + default_branch = "main" + repository_team_permissions_override = {} + protected_branches = [ + { + pattern = "main" + enforce_admins = true + require_signed_commits = true + required_linear_history = true + allow_force_pushes = false + allow_deletions = false + require_conversation_resolution = true + + required_pull_request_reviews = { + dismiss_stale_reviews = true + restrict_dismissals = false + dismissal_restrictions = [] + require_code_owner_reviews = true + required_approving_review_count = 2 + require_last_push_approval = true + } + + required_status_checks = { + strict = true + contexts = ["ci/test", "ci/build"] + } + } + ] + advance_security = true + has_vulnerability_alerts = true + topics = ["example", "application", "production"] + homepage = "https://app.example.com" + delete_head_on_merge = true + allow_auto_merge = false # Disabled for production repos + dependabot_security_updates = true + } + } +} diff --git a/organizations/projects/example-project/example-org/teams/terragrunt.hcl b/organizations/projects/example-project/example-org/teams/terragrunt.hcl new file mode 100644 index 0000000..09524f9 --- /dev/null +++ b/organizations/projects/example-project/example-org/teams/terragrunt.hcl @@ -0,0 +1,79 @@ +# Example team configuration +# This file demonstrates how to configure teams for a project using the team_set module + +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "providers" { + path = "${get_repo_root()}/organizations/providers/${basename(dirname(dirname(get_terragrunt_dir())))}/providers.hcl" + expose = true +} + +terraform { + source = "github.com/FociSolutions/github-foundations-modules//modules/team_set" +} + +inputs = { + teams = { + # Administrative team + "example-admins" = { + name = "Example Admins" + description = "Administrative team for the example project" + privacy = "closed" # Options: closed, secret + members = [ + "admin1", + "admin2" + ] + maintainers = [ + "admin1" + ] + } + + # Developer team + "example-developers" = { + name = "Example Developers" + description = "Developer team for the example project" + privacy = "closed" + members = [ + "developer1", + "developer2", + "developer3", + "developer4" + ] + maintainers = [ + "developer1", + "developer2" + ] + } + + # Read-only team + "example-viewers" = { + name = "Example Viewers" + description = "Read-only access team for the example project" + privacy = "closed" + members = [ + "viewer1", + "viewer2" + ] + maintainers = [ + "viewer1" + ] + } + + # Security team + "example-security" = { + name = "Example Security" + description = "Security team responsible for code reviews and security updates" + privacy = "secret" # Secret teams are only visible to organization owners and team members + members = [ + "security1", + "security2" + ] + maintainers = [ + "security1" + ] + } + } +} diff --git a/organizations/providers/example-org/providers.hcl b/organizations/providers/example-org/providers.hcl new file mode 100644 index 0000000..53f8ab8 --- /dev/null +++ b/organizations/providers/example-org/providers.hcl @@ -0,0 +1,36 @@ +# Example provider configuration for an organization +# This file demonstrates how to configure the GitHub provider for a specific organization + +locals { + organization_name = "example-org" + secret_manager_project = get_env("GCP_SECRET_MANAGER_PROJECT") +} + +generate "github_provider" { + path = "provider.tf" + if_exists = "overwrite" + contents = < 0 + ]) + error_message = "Each team must have at least one maintainer." + } + + validation { + condition = alltrue([ + for team_slug, team in var.teams : + alltrue([for maintainer in team.maintainers : contains(team.members, maintainer)]) + ]) + error_message = "All team maintainers must also be team members." + } +} + +# Output validation results +output "validation_passed" { + description = "Indicates if all validations passed" + value = true +} + +output "organization_name" { + description = "Validated organization name" + value = var.organization_settings.name +} + +output "repository_count" { + description = "Total number of repositories configured" + value = length(var.public_repositories) + length(var.private_repositories) +} + +output "team_count" { + description = "Total number of teams configured" + value = length(var.teams) +} + +output "security_settings" { + description = "Organization security settings summary" + value = { + advance_security_enabled = var.organization_settings.advance_security_enabled_for_new_repositories + secret_scanning_enabled = var.organization_settings.secret_scanning_enabled_for_new_repositories + secret_push_protection_enabled = var.organization_settings.secret_scanning_push_protection_enabled_for_new_repositories + dependabot_alerts_enabled = var.organization_settings.dependabot_alerts_enabled_for_new_repositories + dependabot_updates_enabled = var.organization_settings.dependabot_security_updates_enabled_for_new_repositories + } +}