diff --git a/README.md b/README.md index fd45098..98513ee 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,10 @@ release set. Override individual selectors with `runtime.sitectl.package_versions` when intentionally testing or promoting a different compatible release set. -All non-ISLE presets use the coordinated sitectl v1.0.0 core/plugin release. -ISLE intentionally remains on its last released compatibility set—sitectl -v0.40.0, sitectl-drupal v0.12.0, and sitectl-isle v0.19.0—until its remaining -components are ready for a coordinated v1 release. Keep ISLE on that complete -set rather than mixing its pre-v1 plugin with v1 packages. +All presets use their coordinated sitectl v1.0.0 core/plugin release set. The +ISLE preset selects the `libops/isle` v1.1.0 template; every other application +preset remains on its v1.0.0 template contract. Keep each preset's complete +template and package set together when promoting an override. GCP deployments have two Terraform ownership layers. Apply [`modules/gcp-foundation`](modules/gcp-foundation/README.md) once per service @@ -64,7 +63,7 @@ No resources. | [name](#input\_name) | Deployment name. | `string` | n/a | yes | | [cloud\_provider](#input\_cloud\_provider) | Compatibility selector for the root GCP entrypoint. Use providers/do or providers/linode for other clouds. | `string` | `"gcp"` | no | | [gcp](#input\_gcp) | Google Cloud infrastructure settings. |
object({
project_id = optional(string, "")
project_number = optional(string, "")
region = optional(string, "us-east5")
zone = optional(string, "us-east5-b")
identity = optional(object({
vm_service_account_email = optional(string, "")
app_service_account_email = optional(string, "")
app_credentials_enabled = optional(bool, false)
}), {})
instance = optional(object({
machine_type = optional(string, "n4-standard-2")
os = optional(string, "cos-125-19216-220-185")
production = optional(bool, false)
}), {})
disks = optional(object({
type = optional(string, "hyperdisk-balanced")
docker_volumes_size_gb = optional(number, 50)
}), {})
network = optional(object({
create = optional(bool, true)
project_id = optional(string, "")
name = optional(string, "")
subnetwork = optional(string, "")
ip_cidr_range = optional(string, "10.42.0.0/24")
mtu = optional(number, 1460)
power_button_allowed_ips = optional(list(string), [])
power_button_ip_depth = optional(number)
ssh_ipv4 = optional(list(string), [])
ssh_ipv6 = optional(list(string), [])
}), {})
snapshots = optional(object({
enabled = optional(bool, false)
}), {})
overlay = optional(object({
source_instance = optional(string, "")
volume_names = optional(list(string), [])
}), {})
cloud_init = optional(object({
initcmd = optional(list(string), [])
runcmd = optional(list(string), [])
}), {})
artifact_registry = optional(object({
repository = optional(string, "")
location = optional(string, "us")
}), {})
power_management = optional(object({
enabled = optional(bool, false)
start_role = optional(string, "")
suspend_role = optional(string, "")
frontend = optional(object({
image = string
port = optional(number, 8080)
cpu = optional(string, "1000m")
memory = optional(string, "1Gi")
}), null)
}), {})
rollout = optional(object({
enabled = optional(bool, false)
release_url = optional(string, "")
release_sha256 = optional(string, "")
port = optional(number, 8081)
jwks_uri = optional(string, "")
jwt_audience = optional(string, "")
custom_claims = optional(string, "")
allowed_ipv4 = optional(list(string), ["10.0.0.0/8"])
}), {})
}) | `{}` | no |
-| [runtime](#input\_runtime) | Provider-neutral compose/runtime settings. | object({
rootfs = optional(string, "")
rootfs_archive_url = optional(string, "")
rootfs_archive_sha256 = optional(string, "")
users = optional(map(list(string)), {})
compose = optional(object({
primary = optional(string, "")
ingress_port = optional(number, 80)
ingress = optional(object({
letsencrypt = optional(bool, false)
bot_mitigation = optional(bool, false)
mode = optional(string, "")
domain = optional(string, "")
acme_email = optional(string, "")
trusted_ips = optional(list(string), [])
max_upload_size = optional(string, "")
upload_timeout = optional(string, "")
}), {})
repo = optional(string, "")
branch = optional(string, "main")
projects = optional(map(object({
docker_compose_repo = string
docker_compose_branch = optional(string)
project_dir = optional(string)
compose_project_name = optional(string)
ingress_port = optional(number)
ingress = optional(object({
letsencrypt = optional(bool)
bot_mitigation = optional(bool)
mode = optional(string)
domain = optional(string)
acme_email = optional(string)
trusted_ips = optional(list(string))
max_upload_size = optional(string)
upload_timeout = optional(string)
}), {})
sitectl_context_name = optional(string)
sitectl_plugin = optional(string)
sitectl_environment = optional(string)
sitectl_packages = optional(list(string))
sitectl_verify_args = optional(list(string))
docker_compose_init = optional(list(string))
docker_compose_up = optional(list(string))
docker_compose_down = optional(list(string))
docker_compose_rollout = optional(list(string))
})), {})
init = optional(list(string))
up = optional(list(string))
down = optional(list(string))
rollout = optional(list(string))
}), {})
sitectl = optional(object({
packages = optional(list(string))
version = optional(string, "latest")
package_versions = optional(map(string), {})
context_name = optional(string, "")
plugin = optional(string, "core")
environment = optional(string, "production")
verify_args = optional(list(string), [])
}), {})
docker = optional(object({
# renovate: datasource=github-releases depName=docker-compose packageName=docker/compose versioning=semver
compose_version = optional(string, "v5.3.1")
# renovate: datasource=github-releases depName=docker-buildx packageName=docker/buildx versioning=semver
buildx_version = optional(string, "v0.35.0")
}), {})
managed_runtime = optional(object({
enabled = optional(bool, true)
internal_services_enabled = optional(bool, false)
internal_services_auto_update = optional(bool, false)
artifacts = optional(list(object({
name = string
url = string
sha256 = string
path = string
mode = optional(string, "0755")
owner = optional(string, "root")
group = optional(string, "root")
restart = optional(string, "")
})), [])
}), {})
vault = optional(object({
addr = optional(string, "")
namespace = optional(string, "")
role = optional(string, "")
agent_enabled = optional(bool, false)
auth_method = optional(string, "auto")
gcp_auth_mount_path = optional(string, "auth/gcp")
agent_token_path = optional(string, "/mnt/disks/data/vault/token")
agent_additional_config = optional(string, "")
agent_templates = optional(list(object({
destination = string
contents = string
perms = optional(string, "0640")
command = optional(string, "")
})), [])
}), {})
extra_env = optional(map(string), {})
}) | `{}` | no |
+| [runtime](#input\_runtime) | Provider-neutral compose/runtime settings. | object({
rootfs = optional(string, "")
rootfs_archive_url = optional(string, "")
rootfs_archive_sha256 = optional(string, "")
users = optional(map(list(string)), {})
compose = optional(object({
primary = optional(string, "")
ingress_port = optional(number, 80)
ingress = optional(object({
letsencrypt = optional(bool, false)
bot_mitigation = optional(bool, false)
mode = optional(string, "")
domain = optional(string, "")
acme_email = optional(string, "")
trusted_ips = optional(list(string), [])
max_upload_size = optional(string, "")
upload_timeout = optional(string, "")
}), {})
repo = optional(string, "")
branch = optional(string, "")
projects = optional(map(object({
docker_compose_repo = string
docker_compose_branch = optional(string)
project_dir = optional(string)
compose_project_name = optional(string)
ingress_port = optional(number)
ingress = optional(object({
letsencrypt = optional(bool)
bot_mitigation = optional(bool)
mode = optional(string)
domain = optional(string)
acme_email = optional(string)
trusted_ips = optional(list(string))
max_upload_size = optional(string)
upload_timeout = optional(string)
}), {})
sitectl_context_name = optional(string)
sitectl_plugin = optional(string)
sitectl_environment = optional(string)
sitectl_packages = optional(list(string))
sitectl_verify_args = optional(list(string))
docker_compose_init = optional(list(string))
docker_compose_up = optional(list(string))
docker_compose_down = optional(list(string))
docker_compose_rollout = optional(list(string))
})), {})
init = optional(list(string))
up = optional(list(string))
down = optional(list(string))
rollout = optional(list(string))
}), {})
sitectl = optional(object({
packages = optional(list(string))
version = optional(string, "latest")
package_versions = optional(map(string), {})
context_name = optional(string, "")
plugin = optional(string, "core")
environment = optional(string, "production")
verify_args = optional(list(string), [])
}), {})
docker = optional(object({
# renovate: datasource=github-releases depName=docker-compose packageName=docker/compose versioning=semver
compose_version = optional(string, "v5.3.1")
# renovate: datasource=github-releases depName=docker-buildx packageName=docker/buildx versioning=semver
buildx_version = optional(string, "v0.35.0")
}), {})
managed_runtime = optional(object({
enabled = optional(bool, true)
internal_services_enabled = optional(bool, false)
internal_services_auto_update = optional(bool, false)
artifacts = optional(list(object({
name = string
url = string
sha256 = string
path = string
mode = optional(string, "0755")
owner = optional(string, "root")
group = optional(string, "root")
restart = optional(string, "")
})), [])
}), {})
vault = optional(object({
addr = optional(string, "")
namespace = optional(string, "")
role = optional(string, "")
agent_enabled = optional(bool, false)
auth_method = optional(string, "auto")
gcp_auth_mount_path = optional(string, "auth/gcp")
agent_token_path = optional(string, "/mnt/disks/data/vault/token")
agent_additional_config = optional(string, "")
agent_templates = optional(list(object({
destination = string
contents = string
perms = optional(string, "0640")
command = optional(string, "")
})), [])
}), {})
extra_env = optional(map(string), {})
}) | `{}` | no |
| [template](#input\_template) | Optional compose template preset. Supported values are archivesspace, ojs, isle, drupal, wp, omeka-s, and omeka-classic. Explicit runtime settings override preset defaults. | `string` | `""` | no |
## Outputs
diff --git a/ansible/README.md b/ansible/README.md
index ab7285f..603885c 100644
--- a/ansible/README.md
+++ b/ansible/README.md
@@ -90,7 +90,7 @@ all:
sitectl:
environment: production
package_versions:
- sitectl-isle: v0.19.0
+ sitectl-isle: v1.0.0
wp-prod.example.edu:
ansible_user: debian
cloud_compose_name: wp-prod
diff --git a/ci/config-management-smoke-inner.sh b/ci/config-management-smoke-inner.sh
index 8489319..63ef32d 100755
--- a/ci/config-management-smoke-inner.sh
+++ b/ci/config-management-smoke-inner.sh
@@ -262,9 +262,9 @@ assert env["DOCKER_COMPOSE_REPO"] == "https://github.com/libops/isle"
assert env["SITECTL_PLUGIN"] == "isle"
assert "sitectl-isle" in env["SITECTL_PACKAGES"].split()
assert json.loads(env["SITECTL_PACKAGE_VERSIONS"]) == {
- "sitectl": "v0.40.0",
- "sitectl-drupal": "v0.12.0",
- "sitectl-isle": "v0.19.0",
+ "sitectl": "v1.0.0",
+ "sitectl-drupal": "v1.0.0",
+ "sitectl-isle": "v1.0.0",
}
assert project["docker_compose_repo"] == "https://github.com/libops/isle"
assert project["project_dir"] == "/mnt/disks/data/libops/isle/main"
diff --git a/ci/terraform-validate.sh b/ci/terraform-validate.sh
index 977e2d1..17e0156 100644
--- a/ci/terraform-validate.sh
+++ b/ci/terraform-validate.sh
@@ -34,10 +34,10 @@ validate_public_provider_graph() {
expected_sources=$'hashicorp/cloudinit\nhashicorp/google\nhashicorp/time'
;;
providers/do)
- expected_sources=$'digitalocean/digitalocean\nhashicorp/cloudinit'
+ expected_sources='digitalocean/digitalocean'
;;
providers/linode)
- expected_sources=$'hashicorp/cloudinit\nlinode/linode'
+ expected_sources='linode/linode'
;;
*)
return 0
diff --git a/docs/managed-runtime.md b/docs/managed-runtime.md
index d418ff9..630426f 100644
--- a/docs/managed-runtime.md
+++ b/docs/managed-runtime.md
@@ -26,10 +26,11 @@ core and plugins independently. The provider-neutral
backward-compatible fallback only for an installed package with neither a
template selector nor an explicit per-package selector.
-The ISLE preset is an intentional temporary exception to the v1 defaults. It
-stays on sitectl v0.40.0, sitectl-drupal v0.12.0, and sitectl-isle v0.19.0 until
-the remaining ISLE components can ship together as v1. Do not combine the
-pre-v1 ISLE plugin with the v1 core or Drupal plugin.
+All presets select coordinated sitectl v1 release packages. The ISLE preset
+uses the `libops/isle` v1.1.0 template with sitectl, sitectl-drupal, and
+sitectl-isle v1.0.0. Every other application preset remains on its v1.0.0
+template contract. Override the template or package selectors only as one
+reviewed, compatible release set.
Omitting `runtime.sitectl.packages` selects the template's package set. An
explicit list replaces that set; `packages = []` or `packages = ["sitectl"]`
@@ -50,9 +51,9 @@ runtime = {
"sitectl-isle",
]
package_versions = {
- sitectl = "v0.40.0"
- sitectl-drupal = "v0.12.0"
- sitectl-isle = "v0.19.0"
+ sitectl = "v1.0.0"
+ sitectl-drupal = "v1.0.0"
+ sitectl-isle = "v1.0.0"
}
plugin = "isle"
}
diff --git a/docs/runtime-contracts.md b/docs/runtime-contracts.md
index 927e7db..9ad177c 100644
--- a/docs/runtime-contracts.md
+++ b/docs/runtime-contracts.md
@@ -122,7 +122,9 @@ The generated app env file exports `COMPOSE_BIND_PORT` for that purpose.
`docker_compose_branch` (the `runtime.compose.branch` input at the public
module boundary) accepts either a branch/tag name or a full 40-character Git
-commit. The source-preparation and `init` phases follow a configured moving ref.
+commit. When the public input is omitted or empty, the selected template
+preset supplies its reviewed branch; the no-preset registry default remains
+`main`. The source-preparation and `init` phases follow a configured moving ref.
An ordinary `up` or service restart instead validates and preserves the commit
selected by the last successful init or rollout. This keeps a detached feature
or pull-request deployment operable until an explicit rollout selects another
diff --git a/internal/contracttest/template_version_test.go b/internal/contracttest/template_version_test.go
index afc30ad..ba1b401 100644
--- a/internal/contracttest/template_version_test.go
+++ b/internal/contracttest/template_version_test.go
@@ -14,6 +14,7 @@ type templateRegistry struct {
type templateDefinition struct {
Branch string `json:"branch"`
+ ExtraEnv map[string]string `json:"extra_env"`
Packages []string `json:"packages"`
PackageVersions map[string]string `json:"package_versions"`
}
@@ -39,12 +40,10 @@ func TestTemplateVersionContract(t *testing.T) {
"sitectl": "v1.0.0",
"sitectl-drupal": "v1.0.0",
},
- // ISLE remains on its last released pre-v1 compatibility set until
- // the outstanding ISLE components are ready for a coordinated v1.
"isle": {
- "sitectl": "v0.40.0",
- "sitectl-drupal": "v0.12.0",
- "sitectl-isle": "v0.19.0",
+ "sitectl": "v1.0.0",
+ "sitectl-drupal": "v1.0.0",
+ "sitectl-isle": "v1.0.0",
},
"ojs": {
"sitectl": "v1.0.0",
@@ -81,8 +80,19 @@ func TestTemplateVersionContract(t *testing.T) {
if !maps.Equal(definition.PackageVersions, expected) {
t.Errorf("template %q package versions diverged:\nexpected %s\nactual %s", name, prettyJSON(t, expected), prettyJSON(t, definition.PackageVersions))
}
- if definition.Branch != "v1.0.0" {
- t.Errorf("template %q branch = %q, want stable contract v1.0.0", name, definition.Branch)
+ expectedBranch := "v1.0.0"
+ if name == "isle" {
+ expectedBranch = "v1.1.0"
+ }
+ if definition.Branch != expectedBranch {
+ t.Errorf("template %q branch = %q, want stable contract %s", name, definition.Branch, expectedBranch)
+ }
+ expectedExtraEnv := map[string]string{}
+ if name == "isle" {
+ expectedExtraEnv["ISLANDORA_TAG"] = "6.3.19"
+ }
+ if !maps.Equal(definition.ExtraEnv, expectedExtraEnv) {
+ t.Errorf("template %q application environment diverged:\nexpected %s\nactual %s", name, prettyJSON(t, expectedExtraEnv), prettyJSON(t, definition.ExtraEnv))
}
}
@@ -122,6 +132,7 @@ func TestTemplateVersionContract(t *testing.T) {
requireContains(t, content, "if contains(keys(local.template.package_versions), package)", relativePath+" template package-version filter")
requireContains(t, content, "package_versions = merge(local.template_sitectl_package_versions, local.input_sitectl.package_versions)", relativePath+" explicit package-version override")
requireContains(t, content, "local.input_sitectl.packages == null ? local.template.packages : local.input_sitectl.packages", relativePath+" omitted-package handling")
+ requireContains(t, content, "extra_env = merge(try(local.template.extra_env, {}), var.runtime.extra_env)", relativePath+" template application environment merge")
}
for _, relativePath := range []string{"examples/binpack/main.tf", "docs/examples.md"} {
diff --git a/main.tf b/main.tf
index 74fa2e2..dab7d7c 100644
--- a/main.tf
+++ b/main.tf
@@ -40,6 +40,7 @@ locals {
}
runtime = merge(var.runtime, {
+ extra_env = merge(try(local.template.extra_env, {}), var.runtime.extra_env)
compose = merge(local.input_compose, {
repo = (
trimspace(local.input_compose.repo) != ""
diff --git a/providers/do/main.tf b/providers/do/main.tf
index a2a6625..f182566 100644
--- a/providers/do/main.tf
+++ b/providers/do/main.tf
@@ -2,10 +2,6 @@ terraform {
required_version = ">= 1.3.0"
required_providers {
- cloudinit = {
- source = "hashicorp/cloudinit"
- version = "~> 2.3"
- }
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.0"
@@ -35,6 +31,7 @@ locals {
}
runtime = merge(var.runtime, {
+ extra_env = merge(try(local.template.extra_env, {}), var.runtime.extra_env)
compose = merge(local.input_compose, {
repo = (
trimspace(local.input_compose.repo) != ""
diff --git a/providers/do/template_versions.tftest.hcl b/providers/do/template_versions.tftest.hcl
index 103be07..781c11c 100644
--- a/providers/do/template_versions.tftest.hcl
+++ b/providers/do/template_versions.tftest.hcl
@@ -1,4 +1,3 @@
-mock_provider "cloudinit" {}
mock_provider "digitalocean" {}
run "custom_package_set_merges_only_applicable_template_versions" {
@@ -27,6 +26,16 @@ run "custom_package_set_merges_only_applicable_template_versions" {
}
error_message = "The DigitalOcean entrypoint must filter template selectors and preserve explicit overrides."
}
+
+ assert {
+ condition = local.runtime.compose.branch == "v1.1.0"
+ error_message = "The DigitalOcean entrypoint must inherit the ISLE v1.1.0 template branch when no override is supplied."
+ }
+
+ assert {
+ condition = local.runtime.extra_env.ISLANDORA_TAG == "6.3.19"
+ error_message = "The DigitalOcean ISLE preset must supply its required application environment."
+ }
}
run "explicit_core_only_package_set_disables_template_plugins" {
@@ -46,7 +55,7 @@ run "explicit_core_only_package_set_disables_template_plugins" {
assert {
condition = local.runtime.sitectl.packages == tolist(["sitectl"]) && local.runtime.sitectl.package_versions == {
- sitectl = "v0.40.0"
+ sitectl = "v1.0.0"
}
error_message = "The DigitalOcean entrypoint must preserve an explicit core-only package set."
}
diff --git a/providers/do/variables.tf b/providers/do/variables.tf
index 60de3c9..2031d40 100644
--- a/providers/do/variables.tf
+++ b/providers/do/variables.tf
@@ -76,7 +76,7 @@ variable "runtime" {
upload_timeout = optional(string, "")
}), {})
repo = optional(string, "")
- branch = optional(string, "main")
+ branch = optional(string, "")
projects = optional(map(object({
docker_compose_repo = string
docker_compose_branch = optional(string)
diff --git a/providers/gcp/main.tf b/providers/gcp/main.tf
index f81a1f1..308a9d3 100644
--- a/providers/gcp/main.tf
+++ b/providers/gcp/main.tf
@@ -39,6 +39,7 @@ locals {
}
runtime = merge(var.runtime, {
+ extra_env = merge(try(local.template.extra_env, {}), var.runtime.extra_env)
compose = merge(local.input_compose, {
repo = (
trimspace(local.input_compose.repo) != ""
diff --git a/providers/gcp/template_versions.tftest.hcl b/providers/gcp/template_versions.tftest.hcl
index ab65579..dd10162 100644
--- a/providers/gcp/template_versions.tftest.hcl
+++ b/providers/gcp/template_versions.tftest.hcl
@@ -36,6 +36,16 @@ run "custom_package_set_merges_only_applicable_template_versions" {
}
error_message = "The GCP entrypoint must filter template selectors and preserve explicit overrides."
}
+
+ assert {
+ condition = local.runtime.compose.branch == "v1.1.0"
+ error_message = "The GCP entrypoint must inherit the ISLE v1.1.0 template branch when no override is supplied."
+ }
+
+ assert {
+ condition = local.runtime.extra_env.ISLANDORA_TAG == "6.3.19"
+ error_message = "The GCP ISLE preset must supply its required application environment."
+ }
}
run "explicit_core_only_package_set_disables_template_plugins" {
@@ -57,7 +67,7 @@ run "explicit_core_only_package_set_disables_template_plugins" {
assert {
condition = local.runtime.sitectl.packages == tolist(["sitectl"]) && local.runtime.sitectl.package_versions == {
- sitectl = "v0.40.0"
+ sitectl = "v1.0.0"
}
error_message = "The GCP entrypoint must preserve an explicit core-only package set."
}
diff --git a/providers/gcp/variables.tf b/providers/gcp/variables.tf
index d041df4..0cbf042 100644
--- a/providers/gcp/variables.tf
+++ b/providers/gcp/variables.tf
@@ -206,7 +206,7 @@ variable "runtime" {
upload_timeout = optional(string, "")
}), {})
repo = optional(string, "")
- branch = optional(string, "main")
+ branch = optional(string, "")
projects = optional(map(object({
docker_compose_repo = string
docker_compose_branch = optional(string)
diff --git a/providers/linode/main.tf b/providers/linode/main.tf
index f43f9f6..19078c2 100644
--- a/providers/linode/main.tf
+++ b/providers/linode/main.tf
@@ -2,10 +2,6 @@ terraform {
required_version = ">= 1.3.0"
required_providers {
- cloudinit = {
- source = "hashicorp/cloudinit"
- version = "~> 2.3"
- }
linode = {
source = "linode/linode"
version = "~> 4.0"
@@ -35,6 +31,7 @@ locals {
}
runtime = merge(var.runtime, {
+ extra_env = merge(try(local.template.extra_env, {}), var.runtime.extra_env)
compose = merge(local.input_compose, {
repo = (
trimspace(local.input_compose.repo) != ""
diff --git a/providers/linode/template_versions.tftest.hcl b/providers/linode/template_versions.tftest.hcl
index 76f04a4..460b3a2 100644
--- a/providers/linode/template_versions.tftest.hcl
+++ b/providers/linode/template_versions.tftest.hcl
@@ -1,4 +1,3 @@
-mock_provider "cloudinit" {}
mock_provider "linode" {}
run "custom_package_set_merges_only_applicable_template_versions" {
@@ -32,6 +31,16 @@ run "custom_package_set_merges_only_applicable_template_versions" {
}
error_message = "The Linode entrypoint must filter template selectors and preserve explicit overrides."
}
+
+ assert {
+ condition = local.runtime.compose.branch == "v1.1.0"
+ error_message = "The Linode entrypoint must inherit the ISLE v1.1.0 template branch when no override is supplied."
+ }
+
+ assert {
+ condition = local.runtime.extra_env.ISLANDORA_TAG == "6.3.19"
+ error_message = "The Linode ISLE preset must supply its required application environment."
+ }
}
run "explicit_core_only_package_set_disables_template_plugins" {
@@ -56,7 +65,7 @@ run "explicit_core_only_package_set_disables_template_plugins" {
assert {
condition = local.runtime.sitectl.packages == tolist(["sitectl"]) && local.runtime.sitectl.package_versions == {
- sitectl = "v0.40.0"
+ sitectl = "v1.0.0"
}
error_message = "The Linode entrypoint must preserve an explicit core-only package set."
}
diff --git a/providers/linode/variables.tf b/providers/linode/variables.tf
index 4ad3d7d..7d46c50 100644
--- a/providers/linode/variables.tf
+++ b/providers/linode/variables.tf
@@ -88,7 +88,7 @@ variable "runtime" {
upload_timeout = optional(string, "")
}), {})
repo = optional(string, "")
- branch = optional(string, "main")
+ branch = optional(string, "")
projects = optional(map(object({
docker_compose_repo = string
docker_compose_branch = optional(string)
diff --git a/salt/cloud-compose/README.md b/salt/cloud-compose/README.md
index a05e5d4..9c4937e 100644
--- a/salt/cloud-compose/README.md
+++ b/salt/cloud-compose/README.md
@@ -111,7 +111,7 @@ cloud_compose:
sitectl:
environment: production
package_versions:
- sitectl-isle: v0.19.0
+ sitectl-isle: v1.0.0
```
Apply:
diff --git a/template_versions.tftest.hcl b/template_versions.tftest.hcl
index bf9f3c9..b33564c 100644
--- a/template_versions.tftest.hcl
+++ b/template_versions.tftest.hcl
@@ -33,6 +33,11 @@ run "default_template_uses_v1_core" {
}
error_message = "The default template must select the released sitectl v1 core."
}
+
+ assert {
+ condition = local.compose.branch == "main"
+ error_message = "The no-preset path must retain the registry's main branch fallback."
+ }
}
run "non_isle_template_uses_v1_release_set" {
@@ -59,9 +64,14 @@ run "non_isle_template_uses_v1_release_set" {
}
error_message = "Non-ISLE templates must select their coordinated sitectl v1 release set."
}
+
+ assert {
+ condition = local.compose.branch == "v1.0.0"
+ error_message = "Non-ISLE templates must retain their stable v1.0.0 template contract."
+ }
}
-run "isle_template_uses_released_pre_v1_package_set" {
+run "isle_template_uses_v1_release_set" {
command = plan
variables {
@@ -80,11 +90,55 @@ run "isle_template_uses_released_pre_v1_package_set" {
assert {
condition = local.sitectl.package_versions == {
- sitectl = "v0.40.0"
- sitectl-drupal = "v0.12.0"
- sitectl-isle = "v0.19.0"
+ sitectl = "v1.0.0"
+ sitectl-drupal = "v1.0.0"
+ sitectl-isle = "v1.0.0"
}
- error_message = "The Isle template must select its reviewed core and plugin release set by default."
+ error_message = "The ISLE template must select its coordinated sitectl v1 release set by default."
+ }
+
+ assert {
+ condition = local.compose.branch == "v1.1.0"
+ error_message = "The ISLE preset must select the stable v1.1.0 template contract."
+ }
+
+ assert {
+ condition = (
+ length(keys(local.runtime.extra_env)) == 1 &&
+ local.runtime.extra_env.ISLANDORA_TAG == "6.3.19"
+ )
+ error_message = "The ISLE preset must supply the minimum supported Islandora image tag."
+ }
+}
+
+run "explicit_application_environment_overrides_template_defaults" {
+ command = plan
+
+ variables {
+ name = "template-versions"
+ cloud_provider = "gcp"
+ template = "isle"
+ gcp = {
+ project_id = "test-project"
+ project_number = "123456789"
+ }
+ runtime = {
+ rootfs_archive_url = "https://example.invalid/cloud-compose.tar.gz"
+ rootfs_archive_sha256 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ extra_env = {
+ ISLANDORA_TAG = "6.3.20"
+ SITE_LABEL = "repository"
+ }
+ }
+ }
+
+ assert {
+ condition = (
+ length(keys(local.runtime.extra_env)) == 2 &&
+ local.runtime.extra_env.ISLANDORA_TAG == "6.3.20" &&
+ local.runtime.extra_env.SITE_LABEL == "repository"
+ )
+ error_message = "Explicit application environment must override preset defaults without dropping additional values."
}
}
@@ -114,7 +168,7 @@ run "explicit_package_versions_override_template_defaults" {
assert {
condition = local.sitectl.package_versions == {
sitectl = "v0.40.1"
- sitectl-drupal = "v0.12.0"
+ sitectl-drupal = "v1.0.0"
sitectl-isle = "v0.19.1"
}
error_message = "Explicit per-package selectors must override only their matching template defaults."
@@ -146,7 +200,7 @@ run "custom_package_set_filters_template_versions" {
assert {
condition = local.sitectl.package_versions == {
- sitectl = "v0.40.0"
+ sitectl = "v1.0.0"
sitectl-wp = "v0.6.1"
}
error_message = "Template selectors for packages omitted by a custom package set must not reach the runtime."
@@ -175,7 +229,7 @@ run "explicit_core_only_package_set_disables_template_plugins" {
assert {
condition = local.sitectl.packages == tolist(["sitectl"]) && local.sitectl.package_versions == {
- sitectl = "v0.40.0"
+ sitectl = "v1.0.0"
}
error_message = "An explicit core-only package set must not be mistaken for an omitted template package selection."
}
diff --git a/templates/apps.json b/templates/apps.json
index 9d4ea5e..5a8600d 100644
--- a/templates/apps.json
+++ b/templates/apps.json
@@ -4,6 +4,7 @@
"branch": "main",
"plugin": "core",
"packages": ["sitectl"],
+ "extra_env": {},
"package_versions": {
"sitectl": "v1.0.0"
}
@@ -14,6 +15,7 @@
"branch": "v1.0.0",
"plugin": "archivesspace",
"packages": ["sitectl", "sitectl-archivesspace"],
+ "extra_env": {},
"package_versions": {
"sitectl": "v1.0.0",
"sitectl-archivesspace": "v1.0.0"
@@ -24,6 +26,7 @@
"branch": "v1.0.0",
"plugin": "ojs",
"packages": ["sitectl", "sitectl-ojs"],
+ "extra_env": {},
"package_versions": {
"sitectl": "v1.0.0",
"sitectl-ojs": "v1.0.0"
@@ -31,13 +34,16 @@
},
"isle": {
"repo": "https://github.com/libops/isle",
- "branch": "v1.0.0",
+ "branch": "v1.1.0",
"plugin": "isle",
"packages": ["sitectl", "sitectl-drupal", "sitectl-isle"],
+ "extra_env": {
+ "ISLANDORA_TAG": "6.3.19"
+ },
"package_versions": {
- "sitectl": "v0.40.0",
- "sitectl-drupal": "v0.12.0",
- "sitectl-isle": "v0.19.0"
+ "sitectl": "v1.0.0",
+ "sitectl-drupal": "v1.0.0",
+ "sitectl-isle": "v1.0.0"
}
},
"drupal": {
@@ -45,6 +51,7 @@
"branch": "v1.0.0",
"plugin": "drupal",
"packages": ["sitectl", "sitectl-drupal"],
+ "extra_env": {},
"package_versions": {
"sitectl": "v1.0.0",
"sitectl-drupal": "v1.0.0"
@@ -55,6 +62,7 @@
"branch": "v1.0.0",
"plugin": "wp",
"packages": ["sitectl", "sitectl-wp"],
+ "extra_env": {},
"package_versions": {
"sitectl": "v1.0.0",
"sitectl-wp": "v1.0.0"
@@ -65,6 +73,7 @@
"branch": "v1.0.0",
"plugin": "omeka-s",
"packages": ["sitectl", "sitectl-omeka-s"],
+ "extra_env": {},
"package_versions": {
"sitectl": "v1.0.0",
"sitectl-omeka-s": "v1.0.0"
@@ -75,6 +84,7 @@
"branch": "v1.0.0",
"plugin": "omeka-classic",
"packages": ["sitectl", "sitectl-omeka-classic"],
+ "extra_env": {},
"package_versions": {
"sitectl": "v1.0.0",
"sitectl-omeka-classic": "v1.0.0"
diff --git a/tests/config-management/ansible/smoke.yml b/tests/config-management/ansible/smoke.yml
index 64a11ee..06761bf 100644
--- a/tests/config-management/ansible/smoke.yml
+++ b/tests/config-management/ansible/smoke.yml
@@ -47,9 +47,9 @@
sitectl:
environment: production
package_versions:
- sitectl: v0.40.0
- sitectl-drupal: v0.12.0
- sitectl-isle: v0.19.0
+ sitectl: v1.0.0
+ sitectl-drupal: v1.0.0
+ sitectl-isle: v1.0.0
managed_runtime:
enabled: false
internal_services_enabled: false
@@ -119,7 +119,7 @@
- '(cloud_compose_application_env_file.content | b64decode | from_json).PORT == "9999"'
- '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].docker_compose_repo == "https://github.com/libops/isle"'
- '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].project_dir == "/mnt/disks/data/libops/isle/main"'
- - '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].compose_project_name == "libops-isle-v1-0-0"'
+ - '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].compose_project_name == "libops-isle-v1-1-0"'
- '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].ingress.domain == "isle.example.edu"'
- '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].sitectl_plugin == "isle"'
- '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].init_commands == []'
diff --git a/variables.tf b/variables.tf
index 56be3f8..9905ee6 100644
--- a/variables.tf
+++ b/variables.tf
@@ -212,7 +212,7 @@ variable "runtime" {
upload_timeout = optional(string, "")
}), {})
repo = optional(string, "")
- branch = optional(string, "main")
+ branch = optional(string, "")
projects = optional(map(object({
docker_compose_repo = string
docker_compose_branch = optional(string)