Compare commits

..

1 Commits

Author SHA1 Message Date
unkinben 8fc9b179a6 feat: add Terraform/OpenTofu registry remote type (#45)
ci/woodpecker/pr/pre-commit Pipeline failed
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
Implements the Terraform Registry Protocol as a proxy remote type so
Terraform and OpenTofu can pull providers through the caching layer
without changing provider source addresses.

- New `terraform` package type with `construct_url` (prepends
  `/v1/providers/`) and `resolve_content` (rewrites `download_url`,
  `shasums_url`, `shasums_signature_url` to route through a companion
  `releases_remote`)
- Built-in mutable pattern for provider version lists
  (`{ns}/{type}/versions`)
- `releases_remote` config option links the registry remote to a
  separate generic remote proxying the release CDN
- Client config: `.terraformrc` / `.tofurc` host block redirects
  `registry.terraform.io` to the proxy without touching `.tf` files
- 8 unit tests + end-to-end test (OpenTofu 1.10 pulling hashicorp/vault
  4.5.0 through docker-compose stack)
- Example config and README section added
2026-05-17 11:25:54 +10:00
+7 -15
View File
@@ -1266,16 +1266,14 @@ class TestTerraformRemote:
def test_download_info_download_url_rewritten(self, client, patched_deps): def test_download_info_download_url_rewritten(self, client, patched_deps):
"""download_url in download-info JSON is rewritten to point to the releases proxy.""" """download_url in download-info JSON is rewritten to point to the releases proxy."""
deps = patched_deps deps = patched_deps
download_info = json.dumps( download_info = json.dumps({
{
"os": "linux", "os": "linux",
"arch": "amd64", "arch": "amd64",
"filename": "terraform-provider-vault_0.28.0_linux_amd64.zip", "filename": "terraform-provider-vault_0.28.0_linux_amd64.zip",
"download_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_linux_amd64.zip", "download_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_linux_amd64.zip",
"shasums_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_SHA256SUMS", "shasums_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_SHA256SUMS",
"shasums_signature_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_SHA256SUMS.sig", "shasums_signature_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_SHA256SUMS.sig",
} }).encode()
).encode()
deps["storage"].exists.return_value = True deps["storage"].exists.return_value = True
deps["storage"].download_object.return_value = download_info deps["storage"].download_object.return_value = download_info
deps["cache"].is_mutable_file.return_value = False deps["cache"].is_mutable_file.return_value = False
@@ -1289,16 +1287,14 @@ class TestTerraformRemote:
def test_download_info_shasums_url_rewritten(self, client, patched_deps): def test_download_info_shasums_url_rewritten(self, client, patched_deps):
"""shasums_url is also rewritten to the releases proxy.""" """shasums_url is also rewritten to the releases proxy."""
deps = patched_deps deps = patched_deps
download_info = json.dumps( download_info = json.dumps({
{
"os": "linux", "os": "linux",
"arch": "amd64", "arch": "amd64",
"filename": "terraform-provider-vault_0.28.0_linux_amd64.zip", "filename": "terraform-provider-vault_0.28.0_linux_amd64.zip",
"download_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_linux_amd64.zip", "download_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_linux_amd64.zip",
"shasums_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_SHA256SUMS", "shasums_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_SHA256SUMS",
"shasums_signature_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_SHA256SUMS.sig", "shasums_signature_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_SHA256SUMS.sig",
} }).encode()
).encode()
deps["storage"].exists.return_value = True deps["storage"].exists.return_value = True
deps["storage"].download_object.return_value = download_info deps["storage"].download_object.return_value = download_info
deps["cache"].is_mutable_file.return_value = False deps["cache"].is_mutable_file.return_value = False
@@ -1315,13 +1311,11 @@ class TestTerraformRemote:
"""The path portion of the upstream URL is preserved when rewriting.""" """The path portion of the upstream URL is preserved when rewriting."""
deps = patched_deps deps = patched_deps
zip_path = "/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_linux_amd64.zip" zip_path = "/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_linux_amd64.zip"
download_info = json.dumps( download_info = json.dumps({
{
"download_url": f"https://releases.hashicorp.com{zip_path}", "download_url": f"https://releases.hashicorp.com{zip_path}",
"shasums_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_SHA256SUMS", "shasums_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_SHA256SUMS",
"shasums_signature_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_SHA256SUMS.sig", "shasums_signature_url": "https://releases.hashicorp.com/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_SHA256SUMS.sig",
} }).encode()
).encode()
deps["storage"].exists.return_value = True deps["storage"].exists.return_value = True
deps["storage"].download_object.return_value = download_info deps["storage"].download_object.return_value = download_info
deps["cache"].is_mutable_file.return_value = False deps["cache"].is_mutable_file.return_value = False
@@ -1338,9 +1332,7 @@ class TestTerraformRemote:
deps["storage"].download_object.return_value = b"PK\x03\x04 zip bytes" deps["storage"].download_object.return_value = b"PK\x03\x04 zip bytes"
deps["cache"].is_mutable_file.return_value = False deps["cache"].is_mutable_file.return_value = False
response = client.get( response = client.get("/api/v1/remote/hashicorp-releases-test/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_linux_amd64.zip")
"/api/v1/remote/hashicorp-releases-test/terraform-provider-vault/0.28.0/terraform-provider-vault_0.28.0_linux_amd64.zip"
)
assert response.status_code == 200 assert response.status_code == 200
assert response.headers["X-Artifact-Source"] == "cache" assert response.headers["X-Artifact-Source"] == "cache"