Last active
June 11, 2023 00:02
-
-
Save SafeEval/0bb39698b8415b1e3626fbf55fff12dd to your computer and use it in GitHub Desktop.
PoC for Terraform Github repo creation with GHAS settings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
############################################################################### | |
# Workaround for Terraform repository creation with Github Advanced Security | |
# feature configuration in dynamic blocks. | |
# | |
# This works, but you have to run Terraform twice for GHAS settings to apply. | |
# - Can switch between public and private visibility. | |
# - Can switch between archived and unarchived. | |
# - Fails when modifying visibility and archived setting simultaneously. | |
# | |
# GHAS API settings depend on existing repository state. Simultaneously modifying | |
# both in the same Terraform resource causes errors. | |
# | |
# registry.terraform.io/hashicorp/github @ 5.26.0 | |
############################################################################### | |
data "github_repository" "existing" { | |
name = "test-repo-tf-ghas-dynamic" | |
} | |
locals { | |
target_visibility = "public" | |
initial_visibility = data.github_repository.existing.visibility | |
visibility_change = local.target_visibility != local.initial_visibility | |
target_archived = false | |
initial_archived = data.github_repository.existing.archived | |
archived_change = local.target_archived != local.initial_archived | |
has_paid_ghas = false | |
ghas_settings = [ | |
{ | |
advanced_security = "enabled" | |
secret_scanning = "enabled" | |
secret_scanning_push_protection = "enabled" | |
} | |
] | |
} | |
# Janky workaround because Terraform lacks a clean raise() assertion feature, | |
# and GHAS settings are tightly coupled with Github repository settings. | |
# https://github.com/hashicorp/terraform/issues/15469 | |
# https://github.com/hashicorp/terraform/pull/25088 | |
resource "null_resource" "simultaneous_visibility_archive_update" { | |
count = !(local.visibility_change && local.archived_change) ? 0 : "Cannot change visibility and archive at the same time" | |
} | |
resource "github_repository" "creation_ghas_dynamic" { | |
# Per-repo configuration. | |
name = "test-repo-tf-ghas-dynamic" | |
description = "TF test: repo creation with ghas=dynamic" | |
visibility = local.target_visibility | |
# Public without paid GHAS: can archive and unarchive. | |
# Private without paid GHAS: can archive and unarchive. | |
# Private to public, active to archived: fails with "403 Repository was archived so is read-only." | |
# Private to public, archived to active: works. | |
# Public to private, active to archived: fails with "403 Repository was archived so is read-only." | |
# Public to private, archived to active: works. | |
archived = local.target_archived | |
auto_init = true | |
# These are only available on public and "enterprise" plan repositories. | |
# Configuring with Terraform dynamic blocks with different conditions. | |
security_and_analysis { | |
# Public without paid GHAS: neither "enabled" or "disabled" work. | |
# Private without paid GHAS: neither "enabled" or "disabled" work. | |
dynamic "advanced_security" { | |
iterator = itr | |
for_each = [ | |
for i in local.ghas_settings: i | |
if (local.has_paid_ghas == true) && (local.initial_visibility == "private") | |
] | |
content { | |
status = itr.value.advanced_security | |
} | |
} | |
# Public without paid GHAS: both "enabled" and "disabled" work. | |
# Private without paid GHAS: neither "enabled" or "disabled" work. | |
dynamic "secret_scanning" { | |
iterator = itr | |
for_each = [ | |
for i in local.ghas_settings: i | |
if (local.has_paid_ghas == true) || ((local.initial_visibility == "public") && (local.target_visibility == "public")) | |
] | |
content { | |
status = itr.value.secret_scanning | |
} | |
} | |
# Public without paid GHAS: both "enabled" and "disabled" work. | |
# Private without paid GHAS: neither "enabled" or "disabled" work. | |
dynamic "secret_scanning_push_protection" { | |
iterator = itr | |
for_each = [ | |
for i in local.ghas_settings: i | |
if (local.has_paid_ghas == true) || ((local.initial_visibility == "public") && (local.target_visibility == "public")) | |
] | |
content { | |
status = itr.value.secret_scanning_push_protection | |
} | |
} | |
} | |
} | |
output "initial_visibility" { | |
value = local.initial_visibility | |
} | |
output "target_visibility" { | |
value = local.target_visibility | |
} | |
output "initial_archived" { | |
value = local.initial_archived | |
} | |
output "target_archived" { | |
value = local.target_archived | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment