Skip to content

Repository files navigation

🐙 GitHub Codespaces Secrets Terraform Module

One secure-by-default boundary for every GitHub Codespaces secret — repository, organization, and user scope — plus the selected-repository allow-list that pairs with selected-visibility org secrets. Private-by-default org visibility, encrypted_value preferred over plaintext, sensitive inputs, and zero secret values in outputs. Built for integrations/github v6.x.

TerraformGitHub providermoduletyperesources


🧩 Overview

This is an aggregation module — a Codespaces secrets bundle. It has no single primary resource; instead it groups four independent, role-named for_each collections behind one boundary, each defaulting to {} so you enable only the scopes you use:

  • 🔑 Repository secrets (repository_secrets) — Codespaces secrets scoped to a single repository.
  • 🏢 Organization secrets (organization_secrets) — org-wide Codespaces secrets with all / private / selected visibility (default private).
  • 🎯 Selected-repository allow-lists (secret_repository_access) — the repository allow-list that a selected-visibility org secret reads from, managed as its own resource.
  • 👤 User secrets (user_secrets) — Codespaces secrets scoped to the authenticated user, optionally granted to specific repositories.

💡 Why it matters: Codespaces secrets feed live developer environments with credentials. This module makes that surface declarative, least-privilege, and auditable — secrets are sensitive inputs, org secrets default to private, and only names and resource ids are ever emitted. It is the direct mirror of terraform-github-dependabot, one scope up to include the user-level secret, so secrets-by-feature stay consistent across Dependabot / Actions / Codespaces.


❤️ Support this project

If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:

Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!


🗺️ Where this fits in the family

The keystone terraform-github-repository emits the repository name (id) and numeric id (repo_id) that this module consumes; the other secret-family siblings consume the same keystone. This module emits only names and ids — to audit/reporting tooling, never to another module's secret input.

flowchart LR
repo["🗝️ terraform-github-repository<br/>keystone"]
cs["🐙 terraform-github-codespaces<br/>(this module)"]
dep["terraform-github-dependabot"]
act["terraform-github-actions-repository"]
audit["📊 Audit / Reporting"]
repo -->|"id = repo name"| cs
repo -->|"repo_id (numeric)"| cs
repo -.-> dep
repo -.-> act
cs -->|"*_secret_names / *_secret_ids"| audit
style cs fill:#8957E5,color:#fff
style repo fill:#24292F,color:#fff
Loading

🔌 Consumes: repository name (repo secrets) and numeric repo_id (org selected allow-lists + user-secret access) from terraform-github-repository. Emits: per-scope secret-name sets and id maps for audit/reporting. See the Cross-Module Contract.


🧬 What this module builds

There is no this resource. The diagram shows the four independent role-named collections; the only internal relationship is that a selected-visibility org secret pairs with the allow-list resource (own that allow-list in exactly one place).

flowchart TD
rs["var.repository_secrets<br/>map(object) — sensitive"] --> repo["github_codespaces_secret.repo<br/>for_each"]
os["var.organization_secrets<br/>map(object) — sensitive"] --> org["github_codespaces_organization_secret.org<br/>for_each"]
sra["var.secret_repository_access<br/>map(object)"] --> allow["github_codespaces_organization_secret_repositories.allow<br/>for_each"]
us["var.user_secrets<br/>map(object) — sensitive"] --> user["github_codespaces_user_secret.user<br/>for_each"]
org -.->|"visibility = selected<br/>allow-list owned in one place"| allow
style repo fill:#8957E5,color:#fff
style org fill:#8957E5,color:#fff
style allow fill:#8957E5,color:#fff
style user fill:#8957E5,color:#fff
Loading

Resource inventory

  • github_codespaces_secret.repo — repository-scoped Codespaces secrets, one per repository_secrets entry.
  • github_codespaces_organization_secret.org — organization-scoped Codespaces secrets with visibility, one per organization_secrets entry.
  • github_codespaces_organization_secret_repositories.allow — the selected-repository allow-list for a selected-visibility org secret, one per secret_repository_access entry.
  • github_codespaces_user_secret.user — user-scoped Codespaces secrets, one per user_secrets entry.

✅ Provider / Versions

  • Terraform>= 1.12.0
  • integrations/github~> 6.0 — validated against 6.12.1
  • Neverhashicorp/github (deprecated). Migrate old state with terraform state replace-provider registry.terraform.io/hashicorp/github registry.terraform.io/integrations/github.

ℹ️ 6.x schema notes surfaced during authoring:

  • No key_id argument. All Codespaces secret resources accept encrypted_value (Base64) and plaintext_valueonly — there is no key_id field. The provider resolves the appropriate Codespaces public key internally. Pre-encrypt against the right public key data source and pass just the encrypted_value.
  • No visibility on user secrets.github_codespaces_user_secret has no visibility; it takes an optional selected_repository_ids that grants repositories access to the secret inside the user's Codespaces.
  • Only created_at / updated_at are computed. These resources expose no node_id, slug, repo_id, or html_url — the cross-module reference is the resource id.

📁 Module Structure

terraform-github-codespaces/
├── providers.tf # github provider requirement (~> 6.0); NO provider {} block
├── variables.tf # four role-named map(object) collections; secret-bearing ones sensitive
├── main.tf # repo / org / allow / user collections (no 'this'); nonsensitive(keys) pattern
├── outputs.tf # per-scope name sets + id maps; NEVER a secret value
├── README.md # this file
└── SCOPE.md # token scopes, prerequisites, consumes/emits contract, gotchas

⚙️ Quick Start

The smallest useful call defines a single repository Codespaces secret. Every collection defaults to {}, so you supply only the scopes you need.

module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"repository_secrets={
npm_token = {
repository ="loan-origination-svc"
secret_name ="NPM_TOKEN"
encrypted_value = var.npm_token_encrypted # Base64, pre-encrypted with the repo Codespaces public key
}
}
}

ℹ️ The organization and authentication are the provider's owner / GITHUB_OWNER and token/App — never module variables. Point the provider at the target org before applying.


🔌 Cross-Module Contract

Sourced directly from SCOPE.md.

Consumes

InputTypeSource
repository_secrets[].repositorystring (repo name)terraform-github-repositoryid
organization_secrets[].selected_repository_idslist(number)terraform-github-repositoryrepo_id
secret_repository_access[].selected_repository_idslist(number)terraform-github-repositoryrepo_id
user_secrets[].selected_repository_idslist(number)terraform-github-repositoryrepo_id

Emits

OutputDescriptionConsumed by
repository_secret_namesSet of managed repo Codespaces secret names (values never emitted)Audit / drift detection
repository_secret_idsMap: handle → github_codespaces_secret resource idReporting
organization_secret_namesSet of managed org Codespaces secret namesAudit
organization_secret_idsMap: handle → github_codespaces_organization_secret resource idReporting
user_secret_namesSet of managed user Codespaces secret namesAudit
user_secret_idsMap: handle → github_codespaces_user_secret resource idReporting
secret_repository_access_idsMap: handle → github_codespaces_organization_secret_repositories resource idReporting

🔒 No secret value is ever output. Only names and resource ids are emitted.


📚 Example Library

Every collection is keyed by a stable caller handle (the map key) — never a list index. Examples use the new GitHub-org source and sibling terraform-github-* references.

1 · Minimal — one repository secret
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"repository_secrets={
npm_token = {
repository ="loan-origination-svc"
secret_name ="NPM_TOKEN"
plaintext_value = var.npm_token # provider encrypts on write
}
}
}

💡 Supply exactly one of plaintext_value or encrypted_value per secret.

2 · Organization secret — visibility = all
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"organization_secrets={
shared_registry = {
secret_name ="SHARED_REGISTRY_TOKEN"
visibility ="all"# every repo in the org, including public
plaintext_value = var.shared_registry_token
}
}
}

⚠️all exposes the secret to every repository, including public ones. Prefer private or selected at a regulated institution.

3 · Organization secret — visibility = private (secure default)
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"organization_secrets={
artifactory = {
secret_name ="ARTIFACTORY_TOKEN"# visibility omitted → defaults to "private" (all private/internal repos)
encrypted_value = var.artifactory_token_encrypted
}
}
}
4 · Organization secret — visibility = selected, allow-list managed separately
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"organization_secrets={
payments_key = {
secret_name ="PAYMENTS_API_KEY"
visibility ="selected"
encrypted_value = var.payments_key_encrypted
# NOTE: do NOT set selected_repository_ids inline — owned by the allow-list below.
}
}
secret_repository_access={
payments_key = {
secret_name ="PAYMENTS_API_KEY"
selected_repository_ids = [12345678, 23456789] # numeric repo ids
}
}
}

🔒 Own each selected secret's allow-list in exactly one place — here, or inline via selected_repository_ids on the secret (example 5), never both.

5 · Organization secret — visibility = selected, allow-list inline
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"organization_secrets={
payments_key = {
secret_name ="PAYMENTS_API_KEY"
visibility ="selected"
encrypted_value = var.payments_key_encrypted
selected_repository_ids = [12345678, 23456789] # inline allow-list
}
}
# Do not also add a secret_repository_access entry for PAYMENTS_API_KEY.
}
6 · User secret
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"user_secrets={
gh_pat = {
secret_name ="PERSONAL_GH_PAT"
plaintext_value = var.personal_gh_pat
}
}
}

ℹ️ User secrets attach to the authenticated user (the provider identity), not the org. They need the codespace:secrets classic scope.

7 · User secret granted to specific repositories
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"user_secrets={
gh_pat = {
secret_name ="PERSONAL_GH_PAT"
encrypted_value = var.personal_gh_pat_encrypted
selected_repository_ids = [12345678] # repos that may read the secret in the user's Codespaces
}
}
}
8 · encrypted_value everywhere (preferred over plaintext)
# Encrypt against the matching Codespaces public key BEFORE Terraform runs.data"github_codespaces_public_key""repo" {
repository="loan-origination-svc"
}
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"repository_secrets={
db_password = {
repository ="loan-origination-svc"
secret_name ="DB_PASSWORD"
encrypted_value = var.db_password_encrypted # Base64, encrypted with the repo public key
}
}
}

🔒 Prefer encrypted_value: the plaintext never enters your HCL. (Note: there is no key_id argument — the provider resolves the public key internally; you supply only the Base64 ciphertext.) State always holds the value regardless — keep your backend encrypted.

9 · for_each at scale — many repo secrets from one map(object)
variable"repo_codespaces_secrets" {
type=map(object({
repository =string
secret_name =string
encrypted_value =string
}))
default={}
sensitive=true
}
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"repository_secrets=var.repo_codespaces_secrets
}

⚠️ Each secret is one API write plus a public-key fetch. Large maps can trip secondary rate limits — split very large applies.

10 · Mixed scopes in a single call
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"repository_secrets={
npm = { repository ="web-portal", secret_name ="NPM_TOKEN", encrypted_value = var.npm_enc }
}
organization_secrets={
artifactory = { secret_name ="ARTIFACTORY_TOKEN", visibility ="private", encrypted_value = var.arti_enc }
}
user_secrets={
gh_pat = { secret_name ="PERSONAL_GH_PAT", encrypted_value = var.pat_enc }
}
}
11 · Repository secrets wired from terraform-github-repository (cross-module)
module"repository" {
source="git::https://github.com/microsoftexpert/terraform-github-repository?ref=v1.0.0"name="loan-origination-svc"visibility="private"
}
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"repository_secrets={
npm_token = {
repository = module.repository.id # repo NAME from the keystone
secret_name ="NPM_TOKEN"
encrypted_value = var.npm_token_encrypted
}
}
}
12 · Selected org secret wired by numeric repo_id (cross-module)
module"repository" {
source="git::https://github.com/microsoftexpert/terraform-github-repository?ref=v1.0.0"name="payments-svc"visibility="private"
}
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"organization_secrets={
payments_key = {
secret_name ="PAYMENTS_API_KEY"
visibility ="selected"
encrypted_value = var.payments_key_encrypted
}
}
secret_repository_access={
payments_key = {
secret_name ="PAYMENTS_API_KEY"
selected_repository_ids = [module.repository.repo_id] # NUMERIC id from the keystone
}
}
}
13 · 🔒 Secure / hardened variant — encrypted everywhere, selected, least repos
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"# Repo secrets: encrypted_value only, never plaintext in code.repository_secrets={
db = {
repository = module.repository.id
secret_name ="DB_PASSWORD"
encrypted_value = var.db_password_encrypted
}
}
# Org secrets: selected visibility, the narrowest possible allow-list.organization_secrets={
payments_key = {
secret_name ="PAYMENTS_API_KEY"
visibility ="selected"
encrypted_value = var.payments_key_encrypted
}
}
secret_repository_access={
payments_key = {
secret_name ="PAYMENTS_API_KEY"
selected_repository_ids = [module.repository.repo_id] # exactly the repos that need it
}
}
}

🔒 Hardened posture: encrypted_value everywhere, org secrets selected (never all), allow-lists scoped to the minimum repositories, secrets are sensitive inputs, no values in outputs.

14 · Consuming the outputs for audit / reporting
module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"#... collections...
}
output"managed_codespaces_secret_names" {
value={
repository = module.codespaces.repository_secret_names
organization = module.codespaces.organization_secret_names
user = module.codespaces.user_secret_names
}
}
# Assert the org never holds an unexpected Codespaces secret (drift detection).check"no_unexpected_org_secret" {
assert {
condition=!contains(module.codespaces.organization_secret_names, "LEGACY_TOKEN")
error_message="A retired Codespaces org secret (LEGACY_TOKEN) is still managed."
}
}

ℹ️ Outputs are names and ids only — never values. Each map/set is empty ({} / []) when its scope is unused, never null.

15 · 🏗️ End-to-end composition (mandatory finale) — repository → codespaces, outputs → inputs
# 1) Keystone repository.module"repository" {
source="git::https://github.com/microsoftexpert/terraform-github-repository?ref=v1.0.0"name="loan-origination-svc"visibility="private"vulnerability_alerts=true
}
# 2) Codespaces secrets wired entirely from the keystone's outputs.module"codespaces" {
source="git::https://github.com/microsoftexpert/terraform-github-codespaces?ref=v1.0.0"# repo name → repository_secrets[].repositoryrepository_secrets={
npm_token = {
repository = module.repository.id
secret_name ="NPM_TOKEN"
encrypted_value = var.npm_token_encrypted
}
}
# org secret, selected visibilityorganization_secrets={
payments_key = {
secret_name ="PAYMENTS_API_KEY"
visibility ="selected"
encrypted_value = var.payments_key_encrypted
}
}
# numeric repo_id → allow-listsecret_repository_access={
payments_key = {
secret_name ="PAYMENTS_API_KEY"
selected_repository_ids = [module.repository.repo_id]
}
}
}
output"codespaces_repo_secret_ids" {
value=module.codespaces.repository_secret_ids
}

💡 The keystone emits id (the repo name) and repo_id (the numeric id). The name flows into repo-secret entries; the numeric id flows into selected allow-lists. Apply the repository before the secrets.


📥 Inputs

All four inputs are map(object(...)) keyed by a stable caller handle, each defaulting to {} (independently optional). The three secret-bearing collections are sensitive = true.

  • repository_secrets(sensitive) — repo-scoped secrets. Required per entry: repository, secret_name. Optional: plaintext_value, encrypted_value (supply one; prefer encrypted).
  • organization_secrets(sensitive) — org-scoped secrets. Required: secret_name. Optional: visibility (default private; validated all/private/selected), plaintext_value, encrypted_value, selected_repository_ids (inline allow-list, default []).
  • secret_repository_access(not sensitive) — allow-lists for selected org secrets. Required: secret_name, selected_repository_ids.
  • user_secrets(sensitive) — user-scoped secrets. Required: secret_name. Optional: plaintext_value, encrypted_value, selected_repository_ids (repos granted access, default []).
Full object schemas
variable"repository_secrets" {
type=map(object({
repository =string
secret_name =string
plaintext_value =optional(string)
encrypted_value =optional(string)
}))
default={}
sensitive=true
}
variable"organization_secrets" {
type=map(object({
secret_name =string
visibility =optional(string, "private") # all | private | selected
plaintext_value =optional(string)
encrypted_value =optional(string)
selected_repository_ids =optional(list(number), [])
}))
default={}
sensitive=true# validation: visibility ∈ {all, private, selected}
}
variable"secret_repository_access" {
type=map(object({
secret_name =string
selected_repository_ids =list(number)
}))
default={}
}
variable"user_secrets" {
type=map(object({
secret_name =string
plaintext_value =optional(string)
encrypted_value =optional(string)
selected_repository_ids =optional(list(number), [])
}))
default={}
sensitive=true
}

🧾 Outputs

OutputDescription
repository_secret_idsMap: handle → github_codespaces_secret resource id. Empty {} when unused.
repository_secret_namesSet of managed repository Codespaces secret names.
organization_secret_idsMap: handle → github_codespaces_organization_secret resource id.
organization_secret_namesSet of managed organization Codespaces secret names.
secret_repository_access_idsMap: handle → github_codespaces_organization_secret_repositories resource id.
user_secret_idsMap: handle → github_codespaces_user_secret resource id.
user_secret_namesSet of managed user Codespaces secret names.

🔒 No output is sensitive — and none is a secret value. Only names and resource ids are emitted; structural fields are revealed with nonsensitive. Every map/set is empty (not null) when its scope is unused.


🧠 Architecture Notes

  • Aggregation shape — no this. There is no single dominant resource; each scope is a peer for_each collection named by role (repo, org, allow, user). This mirrors terraform-github-dependabot (repo + org + allow) one scope up, adding github_codespaces_user_secret.
  • sensitive inputs + nonsensitive(keys).repository_secrets, organization_secrets, and user_secrets are sensitive = true because they carry secret values. Terraform forbids for_each over a sensitive value, so main.tf iterates nonsensitive(toset(keys(...))) and indexes the map inside each resource. Non-secret structural fields (repository, secret_name, visibility) are revealed with nonsensitive so plan output and outputs stay useful; the secret value flows straight through to the schema-sensitive plaintext_value / encrypted_value arguments.
  • encrypted_value preferred — and there is no key_id. Prefer encrypted_value (pre-encrypted, Base64) over plaintext_value so plaintext never enters HCL. These resources expose no key_id argument — the provider resolves the Codespaces public key internally. ⚠️ Either way the value lives in state — keep the backend encrypted.
  • Org visibility & the one-place allow-list rule.organization_secrets[].visibility is all / private / selected (default private, validated). For selected, own the allow-list in exactly one place: inline selected_repository_ids on the secret or a secret_repository_access entry — never both for the same secret, or they fight over the same allow-list.
  • Values are write-only; names/ids are the only outputs. The provider cannot read a secret's value back, so it cannot detect remote-value drift — changing a value in code re-writes it; a value changed only in the GitHub UI is invisible to Terraform. Secret names are tracked. On import, the provider does not fetch the value (terraform import github_codespaces_secret.repo[\"handle\"] repo/SECRET_NAME; org/user import by secret name) — you may need ignore_changes on the value as a workaround.
  • No tags, no timeouts. GitHub has no resource tagging concept and these resources expose no timeouts block — there is no tags/timeouts tail (the key difference from the azurerm/aws libraries).

🧱 Design Principles

  • 🔒 Private by default — org-secret visibility defaults to private, never all/public. Wider exposure is an explicit, reviewed opt-in.
  • 🗝️ Encrypt over plaintextencrypted_value is the documented preference so secrets never sit in HCL; plaintext_value is the fallback.
  • 🙈 Secrets are sensitive — every secret-bearing input map is sensitive = true; no secret value is ever emitted as an output.
  • 🎯 Least privilegeselected org secrets scope to the minimum repositories; allow-lists are owned in one place to avoid accidental over-grant.
  • 🧩 Composable, auth-free — no provider {} block, no owner/token/app_auth variables; the caller configures auth and the target org. integrations/github only — never hashicorp/github.
  • 🧾 Auditable — emits exactly the names and ids audit/reporting tooling needs, and nothing more.

🚀 Runbook

terraform init -backend=false
terraform validate
terraform fmt -check
terraform plan
terraform apply
terraform output

⚠️ Always pin the module to a tag — ?ref=v1.0.0never a branch. Codespaces secrets feed live developer environments at a regulated institution; a moving ref is unacceptable.


🧪 Testing

Offline proof gate (no live org required):

terraform fmt -check # zero formatting differences
terraform validate # configuration is valid
tflint # core rules (no dedicated GitHub ruleset exists)

✅ This module passes terraform init -backend=false, terraform validate ("Success! The configuration is valid."), and terraform fmt -check (zero diffs) against integrations/github 6.12.1.


💬 Example Output

repository_secret_ids = {
"npm_token" = "loan-origination-svc:NPM_TOKEN"
}
repository_secret_names = toset([
"NPM_TOKEN",
])
organization_secret_ids = {
"payments_key" = "PAYMENTS_API_KEY"
}
organization_secret_names = toset([
"PAYMENTS_API_KEY",
])
secret_repository_access_ids = {
"payments_key" = "PAYMENTS_API_KEY"
}
user_secret_ids = {}
user_secret_names = toset([])

🔍 Troubleshooting

SymptomCauseResolution
Invalid for_each argument / "sensitive value" on planA secret-bearing map was iterated directlyThe module already uses for_each = nonsensitive(toset(keys(...))); if you adapt it, never for_each a sensitive value directly.
403 / Resource not accessible on org secretsProvider identity lacks org rightsToken/App needs admin:org (classic) or Organization → Codespaces secrets: read/write (fine-grained). See SCOPE.md.
403 on user secretsMissing user scopeClassic PAT needs codespace:secrets; fine-grained needs Codespaces user secrets: read/write on the user.
Apply fails creating any Codespaces secretCodespaces not enabled for the org / not billedEnable Codespaces and configure billing first. Many regulated orgs disable Codespaces — confirm it is part of the footprint.
Org secret apply fails on a Free orgOrg Codespaces secrets need Team / Enterprise CloudUpgrade the plan or scope secrets to repo/user level.
selected_repository_ids rejected / no effectWrong id type, or set on a non-selected secretUse numericrepo_id (wire module.repository.repo_id), and only with visibility = "selected".
Allow-list keeps revertingAllow-list owned in two placesSet selected_repository_ids inline or via secret_repository_access for a given secret — never both.
Value changed in the GitHub UI not detectedValues are write-onlyThe provider can't read values back; re-apply from code (the source of truth), or use ignore_changes for externally-rotated secrets.
Secondary rate limit on a big applyMany secrets = many writes + key fetchesSplit large for_each maps across applies.

🔗 Related Docs

  • integrations/github provider — Codespaces Secret, Codespaces Organization Secret, Codespaces Organization Secret Repositories, and Codespaces User Secret resource references
  • integrations/github provider — Codespaces public-key data sources (repo / organization / user) for encrypted_value
  • module — terraform-github-repository (keystone; emits id and repo_id)
  • module — terraform-github-dependabot (the direct mirror — repo + org + allow-list)
  • module — terraform-github-actions-repository / terraform-github-repository-environment (sibling secrets surfaces)
  • GitHub Docs — Managing encrypted secrets for your Codespaces, and the Codespaces organization/billing policy matrix

Releases

Packages

Contributors

Languages