') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - libre-devops/terraform-github-actions-secrets: 🔐 Manage GitHub Actions secrets and variables across repo/org/environment scope, with optional Key Vault sync · GitHub
Skip to content

Repository files navigation

Libre DevOps

Terraform GitHub Actions Secrets

Manage GitHub Actions secrets and variables across the full scope matrix (repository, organization, environment) from one typed surface, using the integrations/github provider. Each secret takes its value either as a literal or synced from an Azure Key Vault secret, so a vault can be the source of truth for the values a pipeline needs.

CIReleaseTerraform RegistryLicense


Not production grade for secret values (read this)

The GitHub provider has no write-only support for secrets, so the value of every secret this module sets is written to Terraform state (only marked sensitive; the feature request is open). Use it where that is acceptable (local, unshared state), or set genuinely sensitive secrets out of band (gh secret set or a helper) and keep this module for variables and non-sensitive config. Variables are not sensitive and have no such caveat.

What it does

  • Secrets and variables, each keyed by a stable logical name, routed to the right resource by a scope field: repository (default), organization, or environment.
  • Two value sources per secret: a literal value, or a Key Vault secret (key_vault_id + key_vault_secret_name) the module reads and syncs. Exactly one per secret.
  • Input validation for the scope, the required fields per scope, the organization visibility, and the one-source rule.

Providers

integrations/github is the primary provider. hashicorp/azurerm is required because the Key Vault sync reads through it; a caller that never uses the Key Vault source still configures a bare azurerm provider (no Azure call is made unless a Key Vault backed secret is present).

Examples

  • examples/minimal - one repository secret and variable from literals.
  • examples/complete - repository, environment and (gated) organization scopes, plus the (gated) Key Vault sync.

Requirements

NameVersion
terraform>= 1.9.0, < 2.0.0
azurerm>= 4.0.0, < 5.0.0
github>= 6.0.0, < 7.0.0

Providers

NameVersion
azurerm>= 4.0.0, < 5.0.0
github>= 6.0.0, < 7.0.0

Modules

No modules.

Resources

NameType
github_actions_environment_secret.thisresource
github_actions_environment_variable.thisresource
github_actions_organization_secret.thisresource
github_actions_organization_variable.thisresource
github_actions_secret.repositoryresource
github_actions_variable.repositoryresource
azurerm_key_vault_secret.thisdata source

Inputs

NameDescriptionTypeDefaultRequired
secretsGitHub Actions secrets to manage, keyed by a stable logical name.
secret_name the secret name in GitHub (defaults to the map key).
scope repository (default), organization, or environment.
repository required for repository and environment scopes.
environment required for environment scope.
visibility organization scope only: all, private, or selected.
selected_repository_ids organization scope with visibility = selected.
value a literal value (sensitive). Exactly one of value or key_vault_id.
key_vault_id + key_vault_secret_name read the value from a Key Vault secret and sync it
(key_vault_secret_name defaults to secret_name). Needs the azurerm provider
configured with data-plane access to the vault.
map(object({
secret_name = optional(string)
scope = optional(string, "repository")
repository = optional(string)
environment = optional(string)
visibility = optional(string)
selected_repository_ids = optional(list(number))
value = optional(string)
key_vault_id = optional(string)
key_vault_secret_name = optional(string)
}))
{}no
variablesGitHub Actions variables to manage, keyed by a stable logical name.
variable_name the variable name in GitHub (defaults to the map key).
scope repository (default), organization, or environment.
repository required for repository and environment scopes.
environment required for environment scope.
visibility organization scope only: all, private, or selected.
selected_repository_ids organization scope with visibility = selected.
value the variable value.
map(object({
variable_name = optional(string)
scope = optional(string, "repository")
repository = optional(string)
environment = optional(string)
visibility = optional(string)
selected_repository_ids = optional(list(number))
value = string
}))
{}no

Outputs

NameDescription
secret_namesManaged secret names by logical key and scope (values are never exported).
synced_from_key_vaultLogical keys of secrets whose value was synced from Key Vault.
variable_namesManaged variable names by logical key and scope.

About

🔐 Manage GitHub Actions secrets and variables across repo/org/environment scope, with optional Key Vault sync

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages