# StackToIT Assess — gcp-candidates/terraform-dynamic-python-webapp/infra

> FOR REVIEW — generated by StackToIT Assess. Architect review required before any decision.

Generated 2026-11-07 04:24 UTC by stacktoit 0.6.0-13076-ga19ea28c64 (a19ea28c64) · knowledge base 0.394.0 · STACKIT provider 0.121.0 · schema 0.24.0

Run `6f8f72b2-1c34-4cfc-8483-344c41245364` · source digest `sha256:19bfed642d5789ccada81b91d5c36e33175dcafd66dc46b1644ffa105d020000`

Run status: COMPLETE (report published)

Global verification: 12 of 12 invariants PASS; vacuous, they checked nothing: NO_SECURITY_WIDENING, VARIABLE_IDENTITY_PRESERVED, APPLICATION_READY_IMPLIES_REQUIRED_ENV_SECRETS_DEPENDENCIES — the table is in index.html (Evidence), the verdicts in workspace.json (`verification`) and manifest.json (`verification`).

**Validation matrix** — What has been established about this draft, row by row, and what has not. Nothing here approves the draft, asserts that it is equivalent to the source, or says it is safe to apply.

- Source completeness: PARTIAL (source status RUNTIME_TOPOLOGY_PARTIAL)
- Draft generation: GENERATED (the draft is in terraform/)
- StackToIT draft checks: PASSED (20 checks, none found a violation)
- Global invariants: PASSED (12 of 12 invariants PASS; vacuous, they checked nothing: NO_SECURITY_WIDENING, VARIABLE_IDENTITY_PRESERVED, APPLICATION_READY_IMPLIES_REQUIRED_ENV_SECRETS_DEPENDENCIES)
- OpenTofu validation: PASSED (tofu init -backend=false and tofu validate accepted the draft; tofu 1.13.1)
- Output schema validation: PASSED (verified at publish: every JSON file that has a schema is validated against it (see run_verification in manifest.json))
- STACKIT plan: NOT RUN (this build runs no plan against a STACKIT project)
- Architect approval: NOT PROVIDED (no review decision is recorded for this run)
- Semantic equivalence: NOT ASSESSED (this build has no measure for it)
- Safe to apply: NOT ASSERTED (StackToIT never asserts it)

**Run summary** — the numbers the console prints at the end of a run, from the same model as `workspace.json` (`run_summary`).

- Package state: Partially executable migration package
- Plan steps: 10 OpenTofu steps without a decision · 0 OpenTofu steps waiting for decisions · 57 manual carry-over · 2 unsupported · 1 units left to the architect for redesign (manual carry-over here includes the cutover, verification and retirement steps; STACKIT API steps, and Terraform steps that no decision can free, are in none of these counts, which the Execution line below states; manual carry-over counts the longest method of each open data-movement choice)
- Source unit fate: 9 Terraform-only · 2 hybrid · 0 API-only · 4 proposed, switched off · 1 manual · 0 no resource (of 16 units the draft considered: 11 known-present, 5 decided only when OpenTofu plans) (what becomes of each unit the draft considered; the five add up to the units considered, and Terraform-only and hybrid together are the units generated)
- Execution: 10 of the 12 automated steps (OpenTofu or a script) are free of decisions and manual prerequisites (2 require a design decision) · 0 can run as written · 10 of those 10 wait for a value (project_id, containers_machine_type, containers_nodes_max, containers_nodes_min and 7 more) · stages of 12 automated steps: 12 in the draft, 10 free of decisions and manual prerequisites, 0 rest on no default to confirm, no opt-in to answer and no value to supply, 0 are approved (every decision and default confirmed in the decisions file, and no value left to supply) · 10 Terraform · 2 API (2 wait for the opt-in) · 0 design inputs · 55 manual migration work (37 settings in 14 review steps) (counting the longest method of each open data-movement choice; 7 steps of the other methods not counted) · 2 lifecycle (cutover/verify/retire) · 2 refused (of 78 plan steps) (what each step of the plan is; the categories add up to the plan's steps)
- Inputs: 0 design inputs wait · 27 open requests (7 block the draft — inputs-template.yaml marks them, 4 are preferences this build cannot apply — inputs-template.yaml, NOT APPLICABLE IN THIS BUILD, says where to set each) (design inputs are steps of the plan; requests are what the run asks the customer, listed one by one when the run is given an inputs file or a project)
- Source units: 11 (known-present migration units; 5 more decided only when OpenTofu plans: 5 present with the defaults of their variables (a variable can change that))
- Critical open settings: 50 (49 to decide, 1 confirm only; 12 resolved of the 62 the units state; 22 more are open on 5 units decided when OpenTofu plans, not counted here but listed in the decision register (marked: applies only if) — with them the register has 71 critical settings to decide (49 + 22))
- Decisions to review: 6 decisions to make (4 plan decisions, 2 plan statements) · 1 default to confirm · 16 units to review (72 critical settings: 71 to decide (22 of them are conditional), 1 confirm only) (a decision to make is a record of an open plan decision, manual action or plan statement; a default to confirm is such a record whose default option the draft carries out (no step waits for it: a person confirms it or changes it); a unit to review is the review record of the critical settings of one unit that the knowledge base cannot decide (one record for each owner role, each setting an item of it); conditional settings are on units decided only when OpenTofu plans (decisions.json))
- Draft coverage: 11 of 16 units with a generated resource (4 proposed, switched off · 0 need no resource · 1 left for the architect · 13 variables · the 16 are the 11 source units and 5 conditional units)
- Global draft invariants: 12/12 PASS (3 of the passes checked nothing; consistency checks over the draft; not target behaviour)
- tofu validate: PASSED (static validation; not target behaviour)
- Architect approval: NOT PROVIDED
- Safe to apply: NOT ASSERTED

Next:

1. Review the 71 open critical settings: a person decides each (index.html, Decisions page; assurance/critical-semantics.json, critical_semantic_resolution.open). 22 of them belong to units that exist only if a plan-time input holds (critical_semantic_resolution.conditional_open). 1 more is carried by the draft already: confirm only.
2. Review the 4 open plan decisions and 0 manual actions of the draft (index.html, Architecture, Deployment prerequisites). Confirm the 1 default the draft carries out (index.html, Decisions page): no step waits for the answer, a person confirms each or changes it.
3. Review the draft in terraform/: nothing in it is approved, and an architect has to review it before any use.
4. Open index.html in a browser for the unit-by-unit view (offline, nothing is loaded).

**Target platform baseline:** STACKIT Terraform provider 0.121.0 (released 2026-10-22). Every mapping, capability statement and draft refers to this release; the date a newer STACKIT release was last looked for is not recorded in this build, so a release published after the one named here is not reflected here. The JSON files of this run are checked against their published schemas by `stacktoit verify RUN_DIR`; the assess run does not run that check itself.

Source providers: google not locked (UNVERIFIED; knowledge base checked against 8.4.0; identity evidence: PINNED_REGISTRY) · google-beta not locked (UNVERIFIED; knowledge base checked against 8.4.0; identity evidence: PINNED_REGISTRY) · http not locked (UNVERIFIED; no pinned source schema) · random not locked (UNVERIFIED; no pinned source schema) · time not locked (UNVERIFIED; no pinned source schema)

> Note (info; google): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0)

> Note (info; google-beta): no lock file records the version of registry.terraform.io/hashicorp/google-beta, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0)

> Note (info; http, random, time): The knowledge base holds no pinned source schema of this provider, so its version cannot be checked (UNVERIFIED); the row records that the configuration uses it and changes no decision.

## How to read this report

This report uses three different scales. Each answers a different question, and they can disagree on the same unit — that is expected, not a contradiction.

- **Confidence** (HIGH/MEDIUM/LOW, per unit below) — how sure the matched rule is about *this* unit's configuration. Answers: *is this specific mapping decision reliable?*
- **Feasibility** (SUPPORTED/CONDITIONAL/UNSUPPORTED/UNKNOWN, per unit below) — whether the source configuration can be represented on STACKIT at all, and how cleanly. Answers, together with Confidence: *is this mapping usable today?*
- **Target maturity** (GA/BETA/EXPERIMENTAL, shown only when not GA) — a STACKIT provider notice about the target Terraform resource itself. Answers: *will the STACKIT provider change this resource under me, independently of whether the mapping is right?*

This report states each decision, its reason and what you have to do. The working behind it — the semantic surface and property accounting of every unit, every critical-property entry, and the engine's own text for a decision that depends on relations it could not resolve — is in `engineering/analysis-details.md` next to this file; `assessment.json` has all of it in machine-readable form.

## Summary

| | |
|---|---|
| Source files | 18 |
| Resources scanned | 37 |
| Migration units | 11 known-present (11 instances) · 5 conditional |
| Disabled units (count/for_each = 0) | 0 |
| Unit dependencies | 29 |
| Source checks | Built-in source checks passed — OpenTofu validation of the source did not run (LOCK_FILE) |
| Source completeness | RUNTIME_TOPOLOGY_PARTIAL — 5 unit(s) have a count/for_each that is not known statically; whether and how often they exist is decided at plan time |
| Support resources (IAM bindings, URL maps, target proxies, … — used by the units above) | 8 — the draft creates nothing for them; 6 went through the critical-property gate and **20 critical setting(s)** of theirs are left to a person (see "Support resources" below) |
| Terraform helpers (`random_*`, `time_*`, `null_resource`, `local_file`, `tls_*`, …) | 5 — out of scope unless it provisions a unit (0 do): they steer the Terraform run, nothing of them exists in the source cloud |

**Generated secrets (3).** These resources produce a secret when Terraform applies: `random_password.database_user_password`, `random_password.django_admin_password`, `random_password.django_secret_key`. The draft neither recreates them nor carries their value — it exists only in the source Terraform state. Decide for each whether the secret is moved by hand or rotated.

**Source placement (whole estate):** provider regions google `us-central1`, google-beta `us-central1`. Every resource without a region of its own sits there; the draft places every unit in `var.region` (a STACKIT region) — the data residency of the estate changes: confirm it once for the estate.

**Semantic accounting:** 11 of 11 units have a semantic contract (what their source family can state); 0 leave a critical semantic unaccounted, 11 leave one for review or as an accepted loss. 0 units are linked to a resource the knowledge base does not know (uncatalogued-related) and are therefore not decided with certainty.

**Critical resolution:** 12 of 62 critical semantics are resolved; 50 are open in 11 units; 22 more are open on 5 units decided when OpenTofu plans, not counted here but listed in the decision register (marked: applies only if). Accounted is not resolved: the open ones are listed in `assurance/critical-semantics.json`, `critical_semantic_resolution`.

**Property accounting** (a separate, wider check than semantic accounting above: every property value the source sets, not only business-critical semantics — measured because this run wrote a draft): 69 of 69 meaningful properties are accounted for across 11 generated units (5 units the draft writes no block of — no resource needed, carried by a STACKIT API call or left for the architect — are not accounted per property); 0 are **UNACCOUNTED** (silent-drop candidates) in 0 of those units — see each unit's "Property accounting" line below (every UNACCOUNTED property is named there), the counts per unit in engineering/analysis-details.md, or `units[].property_accounting.unaccounted` in assessment.json.

**Critical-property gate:** 70 property entries across the estate need attention (a CRITICAL property with no evidence-backed disposition, an unresolved contradiction, or a property left for review/measured only); 11 of 11 units are not automation-eligible (because of such a property, or an open critical semantic that reads no property of the unit) — see each unit's "critical setting(s) left to you" lines below (grouped by category; every entry in engineering/analysis-details.md), or `units[].property_accounting.critical`/`automation_eligible` in assessment.json.

| Class | Units | Share |
|---|---:|---:|
| DIRECT | 0 | 0% |
| RECONFIGURE | 6 | 54% |
| REPLATFORM | 2 | 18% |
| CONTAINERIZE | 2 | 18% |
| REDESIGN | 0 | 0% |
| MANUAL_REVIEW | 1 | 9% |
| BLOCKED | 0 | 0% |

Confidence: HIGH 0 · MEDIUM 10 · LOW 1

The classes and the confidence count the 11 known-present unit(s); the 5 conditional unit(s) — whether they exist is decided only when a plan runs — are listed under "Uncertainty by cause" with the class each would get.

## Target maturity

Units whose proposed STACKIT target is not generally available in the pinned provider (0.121.0): the provider may change these resources incompatibly or remove them.

| Unit | Target | Maturity | Lifecycle |
|---|---|---|---|
| `google_service_account.automation` | STACKIT service account | EXPERIMENTAL | active |
| `google_service_account.client` | STACKIT service account | EXPERIMENTAL | active |
| `google_service_account.server` | STACKIT service account | EXPERIMENTAL | active |
| `google_cloudbuild_trigger.activategcb` | a workflow in STACKIT Git Pipelines (GitHub Actions syntax, STACKIT-managed or custom runners) or the customer's CI/CD | BETA | active |
| `google_cloudbuild_trigger.init` | a workflow in STACKIT Git Pipelines (GitHub Actions syntax, STACKIT-managed or custom runners) or the customer's CI/CD | BETA | active |
| `google_cloudbuild_trigger.placeholder` | a workflow in STACKIT Git Pipelines (GitHub Actions syntax, STACKIT-managed or custom runners) or the customer's CI/CD | BETA | active |
| `google_firebase_hosting_site.client` | STACKIT Object Storage as origin of a STACKIT CDN distribution, with a custom domain | BETA | active |
| `google_service_account.init` | STACKIT service account | EXPERIMENTAL | active |

BETA: the provider marks the resources beta — "may be subject to breaking changes in the future". EXPERIMENTAL: part of an experimental provider feature — "likely going to undergo significant changes or be removed in the future". Both are notices of the STACKIT Terraform provider, not StackToIT's judgement of the service.

## Target lifecycle

Lifecycle evidence for the STACKIT capabilities some units land on. A state is derived from published dates only, as of the day the sources were read; it is not a verdict on a cluster, and a version or capability without a date has the state UNKNOWN. This report does not read the clock: compare the dates with today.

### SKE Kubernetes versions

Units whose target uses it: `google_cloud_run_v2_job.migrate`, `google_cloud_run_v2_service.server`.

State as of **2026-11-03** (the day the pages were read). Not vouched for after **2027-02-01**: re-read the sources then.

| Version | State | Released | Deprecated | Expires | Production suitability | Upgrade action | Migration timing risk |
|---|---|---|---|---|---|---|---|
| 1.36 | SUPPORTED | 2026-08-27 | not stated | 2027-06-09 | SUITABLE | PLAN | LOW |
| 1.35 | UNKNOWN | not stated | not stated | 2027-02-10 | UNKNOWN | UNKNOWN | UNKNOWN |
| 1.34 | EXPIRED | 2025-12-16 | 2026-08-28 | 2026-10-14 | NOT_SUITABLE | MANDATORY_UPDATE_APPLIES | HIGH |
| 1.33 | EXPIRED | 2025-07-29 | 2026-06-09 | 2026-06-10 (sources disagree: 2026-07-08) | NOT_SUITABLE | MANDATORY_UPDATE_APPLIES | HIGH |
| 1.32 | EXPIRED | not stated | 2026-02-20 | 2026-04-15 | NOT_SUITABLE | MANDATORY_UPDATE_APPLIES | HIGH |

- **Production suitability: SUITABLE.** Suitable as a landing: 1.36. Review before use: none. Not suitable as a landing (ended or ending inside 30 days): 1.34, 1.33, 1.32. No date evidence, so not assessed: 1.35.
- **Upgrade action.** Upgrade before the expiry: none. Plan the upgrade (an end is announced): 1.36. Already expired, the provider's mandatory update applies: 1.34, 1.33, 1.32. No end published, nothing due that the sources show: none.
- **Migration timing risk** (that the end of the landing version falls inside the migration). HIGH: 1.34, 1.33, 1.32. MEDIUM: none. LOW: 1.36. UNKNOWN (an unpublished end is not safety): 1.35.
- **Day-2 responsibility.** When a version reaches its expiry the update is performed by the provider (STACKIT): "If the Kubernetes or OS version of a cluster has reached its expiration date, SKE starts a mandatory update to the highest available patch version of the current minor version, or to the highest patch version of the consecutive minor version that is not classified as preview version." and "mandatory version updates run, even if the auto update for the Kubernetes version is deactivated". Automatic updates otherwise "only update to higher patch levels" in the cluster's maintenance window. Notice: "As a SKE user you will get informed via release notes and via email in case you are operating a cluster with a deprecated Kubernetes version." Customer: "you can check the exact expiration dates for your current Kubernetes and node pool versions in the cluster.status.expiration field via the SKE API". The page does not assign any further duty (workload readiness for the update, testing) to the customer or to STACKIT: not stated.
- **1.36:** The expiry day of 1.36 was not published on 2026-10-08 and is on 2026-11-03; the page has no release column, so the release date is still the one of the release note.
- **1.35:** The pages read give no release date for 1.35 (no release-note entry), so the state stays UNKNOWN: a future expiry date does not say that a version is offered. The 1.34 deprecation entry names 1.35 as the upgrade target, and the SKE API catalogue that ships with this build (fetched 2026-10-18) lists 1.35.8 as supported; the draft of the Kubernetes version reads that catalogue for a row like this one, so a release date is not estimated here.
- **1.34:** Clusters still on 1.34 are upgraded to 1.35 by the mandatory update (release note of 2026-08-28); the day it runs inside the maintenance window is not stated, so no forced-update date is recorded.
- **1.33:** The expiry day differs between the lifecycle page (2026-06-10) and the release note (2026-07-08); the state is EXPIRED under either.
- **1.32:** No release date for 1.32 appears in the pages read.

The 30-day window that makes a version EXPIRING is a StackToIT presentation parameter, not a provider fact.

Sources (read 2026-11-03): https://docs.stackit.cloud/products/runtime/kubernetes-engine/basics/operations/version-updates/; https://docs.stackit.cloud/products/runtime/kubernetes-engine/reference/lifecycle/; https://docs.stackit.cloud/products/runtime/kubernetes-engine/release-notes/.

**Decision axes** (derived from the class, findings and contract): feasibility SUPPORTED 0 · CONDITIONAL 10 · UNSUPPORTED 0 · UNKNOWN 1 (the 11 units counted in the totals). Not counted in the totals, decided only when OpenTofu plans: 5 units — feasibility SUPPORTED 0 · CONDITIONAL 5 · UNSUPPORTED 0 · UNKNOWN 0.

## Modules

The module calls of the source, each read from the units inside it (nested calls are counted in the call that contains them). A module row is a reading of its units' decisions; every unit keeps its own class, confidence and accounting below — nothing is decided at module level. "Depends on" names the module calls whose outputs the call's inputs read — a reading of the source: it orders nothing, the waves stay each unit's own.

| Module call | Source → version | Resources | Units (known-present · conditional · absent) | Classes | Worst | Automation-eligible | Waves | Internals | STACKIT targets | Depends on |
|---|---|---:|---|---|---|---|---|---|---|---|
| `module.project_services` | terraform-google-modules/project-factory/google//modules/project_services 18.0.0 | 3 | 0 · 0 · 0 | — | — | 0 of 0 | — | 0 — see Unit mapping | — | — |

## Source status

- **5 unit(s) have a count/for_each that is not known statically**, so whether and how many instances exist is open: `google_cloudbuild_trigger.activategcb`, `google_cloudbuild_trigger.init`, `google_cloudbuild_trigger.placeholder`, `google_firebase_hosting_site.client`, `google_service_account.init`. The migration plan lists them as prerequisites, not as wave members.

## Uncertainty by cause

5 unit(s) exist only if a plan says so: their count/for_each is not known from the source. They are not counted in the unit totals and the classes above, they are not wave members (the migration plan lists them as prerequisites), they are not automation-eligible, and the class shown for them is the one they would get if they exist. Below, they are grouped by the kind of cause; each group names what decides them and the remedy.

By precision state (`summary.presence.conditional_by_state`; no state says the unit exists): 5 present with the defaults of their variables (a variable can change that).

### A root variable that a variable file or the command line can override — 5 unit(s)

**Remedy.** Only the default of a root variable decides whether this exists on the defaults (a default of 0, false or an empty set switches it off) and how often, and a default is not a fact of the source: a variable file, `-var` or `TF_VAR_<name>` can change it, so it is never read as existing now. Give the variable its value — `--var-file FILE`, or a `terraform.tfvars` / `*.auto.tfvars` next to the source — and assess again; StackToIT then reads that value as the source's.

| Decided by | Units | Which |
|---|---:|---|
| the default of variable `var.init` | 4 | `google_cloudbuild_trigger.activategcb`, `google_cloudbuild_trigger.init`, `google_cloudbuild_trigger.placeholder`, `google_service_account.init` |
| the default of variable `var.random_suffix` | 1 | `google_firebase_hosting_site.client` |

## Blockers

No unit is classified BLOCKED.

## Architect review queue

Units that need a human decision, most severe first.

| Unit | Module | Class | Confidence | Why |
|---|---|---|---|---|
| `google_firebase_project.default` | — | MANUAL_REVIEW | LOW | The enabling of Firebase on a Google Cloud project. WARNING (source-provider-unverified): root: source-provider-unverified:google |
| `google_cloudbuild_trigger.init` | — | REDESIGN | LOW | A Cloud Build trigger starts a build when a source event happens (a push or a pull request on GitHub, Bitbucket Server, a repository of the 2nd generation, Developer Connect or Cloud Source Repositories), when a Pub/Sub message arrives, when a webhook is called or when a person runs it. WARNING (source-provider-unverified): root: source-provider-unverified:google WARNING (linked-dependency-unread): This unit names google_cloud_run_v2_job.migrate (google_cloud_run_v2_job), which the draft carries. WARNING (linked-dependency-unread): This unit names google_cloud_run_v2_service.server (google_cloud_run_v2_service), which the draft carries. +2 more |
| `google_cloudbuild_trigger.placeholder` | — | REDESIGN | LOW | A Cloud Build trigger starts a build when a source event happens (a push or a pull request on GitHub, Bitbucket Server, a repository of the 2nd generation, Developer Connect or Cloud Source Repositories), when a Pub/Sub message arrives, when a webhook is called or when a person runs it. WARNING (source-provider-unverified): root: source-provider-unverified:google WARNING (linked-dependency-unread): This unit names google_firebase_hosting_site.client (google_firebase_hosting_site), whose own decision the target does not carry (it is REDESIGN), and the semantic contract of google_cloudbuild_trigger does not read google_firebase_hosting_site, so what the reference becomes is not assessed. |
| `google_firebase_hosting_site.client` | — | REDESIGN | LOW | A Firebase Hosting site: the unit of hosting, whose identifier builds the Firebase-provided sub-domains, optionally associated with a Firebase web app. WARNING (source-provider-unverified): root: source-provider-unverified:google WARNING (linked-dependency-unread): This unit names google_firebase_project.default (google_firebase_project), whose own decision the target does not carry (it is MANUAL_REVIEW), and the semantic contract of google_firebase_hosting_site does not read google_firebase_project, so what the reference becomes is not assessed. |
| `google_cloudbuild_trigger.activategcb` | — | REDESIGN | MEDIUM | A Cloud Build trigger starts a build when a source event happens (a push or a pull request on GitHub, Bitbucket Server, a repository of the 2nd generation, Developer Connect or Cloud Source Repositories), when a Pub/Sub message arrives, when a webhook is called or when a person runs it. WARNING (source-provider-unverified): root: source-provider-unverified:google |
| `google_cloud_run_v2_job.migrate` | — | CONTAINERIZE | MEDIUM | The job already runs a container image; it becomes a Kubernetes Job on SKE (kubernetes/<job>/manifests.yaml). WARNING (run-unsupported-volume): A container mounts a Cloud SQL connection, a Cloud Storage bucket (through Cloud Storage FUSE) or an NFS share. WARNING (source-provider-unverified): root: source-provider-unverified:google |
| `google_cloud_run_v2_service.server` | — | CONTAINERIZE | MEDIUM | The service already runs a container image, so it moves as a Deployment on SKE (kubernetes/<service>/manifests.yaml): its containers, ports, resources, probes, command, arguments, environment names and secret references, volumes of the kinds a pod can mount, and its range of instances (as a HorizontalPodAutoscaler) are written; Cloud Run injects the PORT variable, so the draft sets it. WARNING (run-unsupported-volume): A container mounts a Cloud SQL connection, a Cloud Storage bucket (through Cloud Storage FUSE) or an NFS share. WARNING (run-iam-policy): A full IAM policy (member/role bindings) is set directly on the service via policy_data; STACKIT has no per-service IAM policy resource, so who may invoke the migrated SKE workload is decided by a person — the draft carries no invocation check. WARNING (source-provider-unverified): root: source-provider-unverified:google |
| `google_pubsub_topic.faux` | — | REPLATFORM | MEDIUM | A topic maps to a RabbitMQ exchange and each subscription to a bound queue. WARNING (source-provider-unverified): root: source-provider-unverified:google |
| `google_sql_database_instance.postgres` | — | REPLATFORM | MEDIUM | Managed PostgreSQL to managed PostgreSQL: data moves with pg_dump/pg_restore or logical replication, the tier becomes a Flex flavor, and authorized networks / private IP become the instance ACL. WARNING (source-provider-unverified): root: source-provider-unverified:google |
| `google_service_account.automation` | — | RECONFIGURE | MEDIUM | A Google service account becomes a STACKIT service account named after its account ID (shortened to the STACKIT name rules, so its e-mail address changes and every reference to it is updated). WARNING (source-provider-unverified): root: source-provider-unverified:google |
| `google_service_account.client` | — | RECONFIGURE | MEDIUM | A Google service account becomes a STACKIT service account named after its account ID (shortened to the STACKIT name rules, so its e-mail address changes and every reference to it is updated). WARNING (source-provider-unverified): root: source-provider-unverified:google |
| `google_service_account.server` | — | RECONFIGURE | MEDIUM | A Google service account becomes a STACKIT service account named after its account ID (shortened to the STACKIT name rules, so its e-mail address changes and every reference to it is updated). WARNING (source-provider-unverified): root: source-provider-unverified:google |
| `google_secret_manager_secret.django_admin_password` | — | RECONFIGURE | MEDIUM | Secrets move to STACKIT Secrets Manager (a Vault-compatible KV store). WARNING (secret-iam-access): The secret has grants for individual principals. WARNING (source-provider-unverified): root: source-provider-unverified:google |
| `google_storage_bucket.media` | — | RECONFIGURE | MEDIUM | A bucket maps to a STACKIT Object Storage bucket. WARNING (gcs-force-destroy): force_destroy lets Terraform delete the bucket together with its objects. WARNING (source-provider-unverified): root: source-provider-unverified:google |
| `google_secret_manager_secret.django_settings` | — | RECONFIGURE | MEDIUM | Secrets move to STACKIT Secrets Manager (a Vault-compatible KV store). WARNING (secret-iam-access): The secret has grants for individual principals. WARNING (source-provider-unverified): root: source-provider-unverified:google |
| `google_service_account.init` | — | RECONFIGURE | MEDIUM | A Google service account becomes a STACKIT service account named after its account ID (shortened to the STACKIT name rules, so its e-mail address changes and every reference to it is updated). WARNING (source-provider-unverified): root: source-provider-unverified:google |

## Unit mapping

### Compute

#### `google_cloud_run_v2_job.migrate`

- **Source:** `google_cloud_run_v2_job` — jobs.tf:18
- **Candidate target:** Kubernetes Job/CronJob on SKE (`stackit_ske_cluster`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Target lifecycle:** provider GA · SKE Kubernetes versions as of 2026-11-03: 1 SUPPORTED, 3 EXPIRED, 1 UNKNOWN — see "Target lifecycle"
- **Classification:** CONTAINERIZE · **Confidence:** MEDIUM · rule `gcp.cloud_run/run-job`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (check run-unsupported-volume, semantic k4-cloud-run-volume-mount-cloud-run-v2-job, semantic cloud-run-v2-job-network-exposure, semantic terraform-destroy-guard and 8 more); a point the scan could not establish
- **Why:** The job already runs a container image; it becomes a Kubernetes Job on SKE (kubernetes/<job>/manifests.yaml). A Cloud Run job runs only when it is executed, so the Job is written suspended and runs when it is unsuspended; its tasks, parallelism and retries become the completions, parallelism and backoff limit of the Job, and what starts the job today (a scheduler, a workflow, a person) starts the Job or a CronJob instead.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-SOURCE-REGION-MAPPING` (alias `convert:estate:source_location:SOURCE_REGION_MAPPING`): Map each source location of the estate to a STACKIT region · The source places its units in a location the scan cannot read (the value comes from an input a plan can change, or the source does not state it). No mapping between Google and STACKIT regions is evidenced, so the region the draft builds in is not shown to hold the residency of a source location: a person states it once for the estate, by answering target.region.source_location for each location.
- **Depends on:** `google_secret_manager_secret.django_settings`, `google_service_account.automation`, `google_sql_database_instance.postgres`
- **INFO** (run-min-zero): The service can scale to zero; on SKE at least one replica runs unless an autoscaler with scale-to-zero (KEDA/Knative) is installed.
- **WARNING** (run-unsupported-volume): A container mounts a Cloud SQL connection, a Cloud Storage bucket (through Cloud Storage FUSE) or an NFS share. The draft writes no volume for these and holds the pods until a person decides: connect to the migrated database or object store over the network instead of the mount, or mount a share or a volume of the cluster yourself.
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (11):** cloud-run-v2-job-network-exposure, deployment-artifact, entry-point, k4-cloud-run-volume-mount-cloud-run-v2-job, location-residency, secrets, service-identity, tc-cloud-run-v2-job-name and 3 more (engineering/analysis-details.md)
- **Property accounting:** 13 of 13 meaningful properties accounted
- **12 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (1; REVIEW 1): `template.template.volumes.cloud_sql_instance.instances` — NOT CARRIED (google_cloud_run_v2_job.migrate): template.template.volumes.cloud_sql_instance.instances — a Cloud Run setting with no counterpart in the draft manifests: Kubernetes has its own rollout, health, scheduling and exec behaviour.
  - identity access (1; REVIEW 1): `template.template.service_account` — NOT CARRIED (google_cloud_run_v2_job.migrate): template.template.service_account — the identity of the revision is a Google service account; the pods run as the default Kubernetes ServiceAccount of the namespace and the draft gives them no identity — decide the identity of the application (the service account unit of the source and the identity decisions of the draft, identity.tf), and the roles it holds on the services it calls.
  - deletion protection (1; REVIEW 1): `deletion_protection` — NOT CARRIED (google_cloud_run_v2_job.migrate): deletion_protection = false — deletion protection is a Google API guard against deleting the resource; the manifests carry no such guard — protect the workload with the access rules of the namespace.
  - secret handling (2; REVIEW 2): `template.template.containers.env.value_source.secret_key_ref.secret`, `template.template.containers.env.value_source.secret_key_ref.version`
  - residency compliance (1; open 1): `location`
  - workload compatibility (6; REVIEW 6): `name`, `template.template.containers.command`, `template.template.containers.env.name`, `template.template.containers.image`, `template.template.containers.volume_mounts.mount_path` and 1 more
- **Why those are open, and what closes them:**
  - `k4-cloud-run-volume-mount-cloud-run-v2-job`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. Where a volume appears in the container, which part of it is mounted there and the gcsfuse flags of a bucket mount (volume_mounts, mount_path and sub_path; volumes, gcs, mount_options). The application opens the bucket or share as a local directory, and the STACKIT draft mounts no volume into a container. Closes when: A person provides the data in the target workload at the path the application expects, with an owner and mode it can use, and checks that it finds its files.
  - `cloud-run-v2-job-network-exposure`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. template.template.vpc_access.egress, template.template.vpc_access.network_interfaces.network, template.template.vpc_access.network_interfaces.subnetwork, template.template.volumes.cloud_sql_instance.instances (network exposure) — what the resource is reachable from and what it can reach. The draft names these settings NOT CARRIED: which database the job mounts and which network its egress goes through are re-created on the target (a database connection, the network of the workload) by a person. A person decides: REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `terraform-destroy-guard`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. deletion_protection of a Cloud Run service, job or worker pool (on unless the source switches it off, which an explicit false states) only stops Terraform from destroying the resource; it is not an API protection. Closes when: A person decides whether the replacement keeps the guard with lifecycle { prevent_destroy = true } in the Terraform code.
  - `service-identity`: Whether the draft carries this setting is decided by its semantic ledger entry "workload identity", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). The Google service account the workload runs as. target.workload.identity asks the customer which model the pods use. Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - `secrets`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. A Secret Manager reference in the environment becomes a secretKeyRef of the Deployment or Job and a secret volume a Kubernetes secret volume, and the head of the manifest lists the Secrets to create. The draft writes no Secret, because no value of a secret reaches an output. Closes when: A person creates the Kubernetes Secrets the manifest lists, filled from STACKIT Secrets Manager (for example with an External Secrets Operator).
  - `location-residency`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The region the service, job or worker pool runs in (google 8.4.0 `location`). A person confirms the region — REVIEW (critical, the value is not verified against the target). Closes when: A person confirms the STACKIT region of the SKE cluster the workload runs on holds the residency the source region gave, since no mapping between Google and STACKIT regions is evidenced.
  - and 5 kinds of reason more (engineering/analysis-details.md)
- **Evidence** (validated against STACKIT product catalogue 2026-09-23 (no managed serverless container platform); terraform-provider-google 8.4.0 (worker_pool added DA4W-UNCLS3-GCP, 2026-09-29)): https://docs.stackit.cloud/products/runtime/kubernetes-engine/ · https://docs.stackit.cloud/products/runtime/cloud-foundry/

#### `google_cloud_run_v2_service.server`

- **Source:** `google_cloud_run_v2_service` — service.tf:17
- **Candidate target:** SKE workload (or Cloud Foundry Docker app) (`stackit_ske_cluster`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Target lifecycle:** provider GA · SKE Kubernetes versions as of 2026-11-03: 1 SUPPORTED, 3 EXPIRED, 1 UNKNOWN — see "Target lifecycle"
- **Classification:** CONTAINERIZE · **Confidence:** MEDIUM · rule `gcp.cloud_run/run-service`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (check run-unsupported-volume, semantic k4-cloud-run-volume-mount-cloud-run-v2-service, semantic iam-invocation, semantic scale-to-zero and 9 more); identity or access mapping (check run-iam-policy, semantic iam-policy-grant); a point the scan could not establish
- **Why:** The service already runs a container image, so it moves as a Deployment on SKE (kubernetes/<service>/manifests.yaml): its containers, ports, resources, probes, command, arguments, environment names and secret references, volumes of the kinds a pod can mount, and its range of instances (as a HorizontalPodAutoscaler) are written; Cloud Run injects the PORT variable, so the draft sets it. Scale-to-zero, scaling on concurrent requests, per-request billing, revisions and traffic splits go away unless Knative or KEDA is operated on SKE.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-SOURCE-REGION-MAPPING` (alias `convert:estate:source_location:SOURCE_REGION_MAPPING`): Map each source location of the estate to a STACKIT region · The source places its units in a location the scan cannot read (the value comes from an input a plan can change, or the source does not state it). No mapping between Google and STACKIT regions is evidenced, so the region the draft builds in is not shown to hold the residency of a source location: a person states it once for the estate, by answering target.region.source_location for each location.
- **Depends on:** `google_secret_manager_secret.django_settings`, `google_service_account.server`, `google_sql_database_instance.postgres`
- **INFO** (run-min-zero): The service can scale to zero; on SKE at least one replica runs unless an autoscaler with scale-to-zero (KEDA/Knative) is installed.
- **WARNING** (run-unsupported-volume): A container mounts a Cloud SQL connection, a Cloud Storage bucket (through Cloud Storage FUSE) or an NFS share. The draft writes no volume for these and holds the pods until a person decides: connect to the migrated database or object store over the network instead of the mount, or mount a share or a volume of the cluster yourself.
- **WARNING** (run-iam-policy): A full IAM policy (member/role bindings) is set directly on the service via policy_data; STACKIT has no per-service IAM policy resource, so who may invoke the migrated SKE workload is decided by a person — the draft carries no invocation check.
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (12):** cloud-sql-connection, deployment-artifact, environment, iam-invocation, iam-policy-grant, k4-cloud-run-volume-mount-cloud-run-v2-service, location-residency, secrets and 4 more (engineering/analysis-details.md) (**not automation-eligible**: no property the unit sets is read by iam-invocation, iam-policy-grant)
- **Property accounting:** 17 of 17 meaningful properties accounted
- **11 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (1; REVIEW 1): `template.volumes.cloud_sql_instance.instances` — NOT CARRIED (google_cloud_run_v2_service.server): template.volumes.cloud_sql_instance.instances — a Cloud Run setting with no counterpart in the draft manifests: Kubernetes has its own rollout, health, scheduling and exec behaviour.
  - identity access (1; REVIEW 1): `template.service_account` — NOT CARRIED (google_cloud_run_v2_service.server): template.service_account — the identity of the revision is a Google service account; the pods run as the default Kubernetes ServiceAccount of the namespace and the draft gives them no identity — decide the identity of the application (the service account unit of the source and the identity decisions of the draft, identity.tf), and the roles it holds on the services it calls.
  - deletion protection (1; REVIEW 1): `deletion_protection` — NOT CARRIED (google_cloud_run_v2_service.server): deletion_protection = false — deletion protection is a Google API guard against deleting the resource; the manifests carry no such guard — protect the workload with the access rules of the namespace.
  - secret handling (3; REVIEW 3): `template.containers.env.value`, `template.containers.env.value_source.secret_key_ref.secret`, `template.containers.env.value_source.secret_key_ref.version`
  - residency compliance (1; open 1): `location`
  - workload compatibility (4; REVIEW 4): `name`, `template.containers.image`, `template.containers.volume_mounts.mount_path`, `template.volumes.name`
- **Why those are open, and what closes them:**
  - `k4-cloud-run-volume-mount-cloud-run-v2-service`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. Where a volume appears in the container, which part of it is mounted there and the gcsfuse flags of a bucket mount (volume_mounts, mount_path and sub_path; volumes, gcs, mount_options). The application opens the bucket or share as a local directory, and the STACKIT draft mounts no volume into a container. Closes when: A person provides the data in the target workload at the path the application expects, with an owner and mode it can use, and checks that it finds its files.
  - `iam-invocation`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. Cloud Run lets only callers with the invoker role through unless the service is made public. The draft carries no invocation check; the SKE exposure and the authentication of callers (application, authenticating proxy, or no exposure at all) are decided by a person. Closes when: A person decides how callers of the workload are authenticated (in the application, behind an authenticating proxy, or by no exposure at all) and how the SKE exposure is set, since the draft carries no invocation check.
  - `iam-policy-grant`: A check of the knowledge base (run iam policy) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). A full IAM policy (member/role bindings) is set directly on the service via policy_data (google 8.4.0); STACKIT has no per-service IAM policy resource, so who may invoke the migrated SKE workload is decided by a person — REVIEW. Closes when: A person decides what this finding asks, and records the evidence or the decision. The finding says: A full IAM policy (member/role bindings) is set directly on the service via policy_data; STACKIT has no per-service IAM policy resource, so who may invoke the migrated SKE workload is decided by a person — the draft carries no invocation check.
  - `terraform-destroy-guard`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. deletion_protection of a Cloud Run service, job or worker pool (on unless the source switches it off, which an explicit false states) only stops Terraform from destroying the resource; it is not an API protection. Closes when: A person decides whether the replacement keeps the guard with lifecycle { prevent_destroy = true } in the Terraform code.
  - `service-identity`: Whether the draft carries this setting is decided by its semantic ledger entry "workload identity", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). The Google service account the workload runs as. target.workload.identity asks the customer which model the pods use. Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - `environment`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The draft writes the environment keys into the ConfigMap and the env of the Deployment or Job. A value is copied only when it is a quantity under a name that says so or a boolean, because any other value can hold a secret, so the rest of the values are a person's. Closes when: A person fills in the values the manifest lists as not copied, in the ConfigMap on the cluster.
  - and 6 kinds of reason more (engineering/analysis-details.md)
- **Evidence** (validated against STACKIT product catalogue 2026-09-23 (no managed serverless container platform); terraform-provider-google 8.4.0 (worker_pool added DA4W-UNCLS3-GCP, 2026-09-29)): https://docs.stackit.cloud/products/runtime/kubernetes-engine/ · https://docs.stackit.cloud/products/runtime/cloud-foundry/

#### `google_cloudbuild_trigger.activategcb`

- **Source:** `google_cloudbuild_trigger` — postdeployment.tf:38
- **Standing:** conditional — whether it exists is decided only when a plan runs; the class below is the one it would get, it is not counted in the totals and not automation-eligible.
- **Candidate target:** a workflow in STACKIT Git Pipelines (GitHub Actions syntax, STACKIT-managed or custom runners) or the customer's CI/CD (`stackit_git`)
- **Target maturity:** BETA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Automation cap:** a target resource is beta (the provider: "may be subject to breaking changes in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_git` (capability `devtools.git`).
- **GA target:** no GA target yet: stackit_git is beta in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** REDESIGN · **Confidence:** MEDIUM · rule `gcp.cloudbuild/cicd-redesign`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (semantic project-residency, semantic build-identity, semantic log-destination, semantic deployment-artifact and 2 more); a point the scan could not establish
- **Why:** A Cloud Build trigger starts a build when a source event happens (a push or a pull request on GitHub, Bitbucket Server, a repository of the 2nd generation, Developer Connect or Cloud Source Repositories), when a Pub/Sub message arrives, when a webhook is called or when a person runs it. The build is a list of container steps (a build block, or a file in the repository) with substitutions, images and artifacts to push, secrets from Secret Manager, a service account, a log destination and optionally a manual approval. STACKIT has no trigger or build resource. The same delivery is a workflow of STACKIT Git Pipelines (workflows written for GitHub Actions; STACKIT-managed or custom runners; secrets from STACKIT Secrets Manager or the repository; a manual-approval action) or the customer's own CI/CD. Nothing is converted: the trigger conditions (branch and tag expressions, file filters, the event kind), the steps (a container step becomes a step or a job with a container), the secrets (created again, never copied), the service account (replaced by the credentials the workflow uses against STACKIT), the log destination and the approval are written again by a person. The pages read describe pipelines that run when changes are pushed; other events (pull requests, schedules, manual runs) are verified against the Forgejo Actions reference.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 2 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-SOURCE-PROJECT-MAPPING` (alias `convert:estate:source_project:SOURCE_PROJECT_MAPPING`): State where the units of each source project of the estate go · The source places its units in the project example-project, and in a project the scan cannot read for some units, and the source project is carried nowhere. A person maps the source projects by answering target.project.source_project for each: var.project_id, or the project of the unit's network (network-project). The answer records that mapping and changes nothing in the draft, which keeps its own project resolver.
  - decision `DEC-GEN-CONVERT-PROPOSED-ALTERNATIVE/google_cloudbuild_trigger.activategcb` (alias `convert:google_cloudbuild_trigger.activategcb:proposal:PROPOSED_ALTERNATIVE`): Decide whether the proposed STACKIT alternative replaces google_cloudbuild_trigger.activategcb: read the module proposals/proposal_activategcb, accept the difference and set its values, or design it another way · the target has no equal of this Cloud Build trigger: starts a build on a source event, a Pub/Sub message, a webhook or by hand, with its steps, substitutions, artifacts, secrets and optional approval: Nothing is converted. The same delivery is a workflow of STACKIT Git Pipelines (written for GitHub Actions; STACKIT-managed or custom runners; secrets from Secrets Manager or the repository; a manual-approval action) or the customer's own CI/CD. Trigger conditions, steps, secrets (created again, never copied), the service account (replaced by the credentials the workflow uses against STACKIT), the log destination and the approval are written again by a person. To decide: Which pipelines are still needed, where they run (STACKIT Git Pipelines or the customer's own CI/CD), how each trigger, step, secret and approval is written again, and who owns the workflow files.
- **Depends on:** `google_pubsub_topic.faux`, `google_service_account.init`
- **INFO** (cloudbuild-source-event): This trigger starts its builds on a Pub/Sub message. The replacement workflow lists the events that start it in its own on: section; the pages of STACKIT read describe pipelines that run whenever changes are pushed to a repository, so a pull request, a schedule or a manual start is verified by a person against the Forgejo Actions reference.
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (6):** project-residency, build-identity, log-destination, deployment-artifact, entry-point, dep-references (**not automation-eligible**: no property the unit sets is read by dep-references)
- **5 critical setting(s) left to you** (not drafted — REDESIGN) — **not automation-eligible**:
  - identity access (1; REVIEW 1): `service_account`
  - audit logging (1; REVIEW 1): `build.options.logging`
  - residency compliance (1; REVIEW 1): `location`
  - workload compatibility (2; REVIEW 2): `build.step.name`, `build.step.script`
- **Why those are open, and what closes them:**
  - `project-residency`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. Project and Cloud Build location are data-residency/project-boundary facts with no STACKIT CI/CD resource to remap them onto -- REVIEW. Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `build-identity`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The service account the build (or the Pub/Sub push notification) runs as; STACKIT Git Pipelines has its own, differently-shaped identity model -- REVIEW. Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `log-destination`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The setting states where/whether build logs are captured or exposed back to GitHub; STACKIT Git Pipelines' own logging model is different -- REVIEW. Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `deployment-artifact`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_cloudbuild_trigger.build.step.name, artifact or image reference (workload compatibility: a setting that binds the code to its runtime stays CRITICAL). Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `entry-point`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_cloudbuild_trigger.build.step.entrypoint, build.step.script, build.step.args, entry point (workload compatibility: a setting that binds the code to its runtime stays CRITICAL). Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `dep-references`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_cloudbuild_trigger and google_cloudbuild_worker_pool names other units or resources (google_cloudbuild_bitbucket_server_config, google_cloudbuild_worker_pool, google_cloudbuildv2_repository, google_compute_global_address, google_compute_network, google_developer_connect_git_repository_link, google_pubsub_topic, google_secret_manager_secret, google_secret_manager_secret_version, google_service_account, google_sourcerepo_repository, google_storage_bucket). A person confirms how the replacement carries the relation between this unit and the units it names, or accepts the difference. Closes when: A person confirms how the replacement carries the relation, or accepts the difference.
- **Review:**
  - [ ] Write the workflow in the repository: one job (or step) per build step, with the same container images or their STACKIT equivalents.
  - [ ] Recreate every secret the build reads in STACKIT Secrets Manager (read with the vault action) or as a repository secret; the values of the source are never copied.
  - [ ] Write the trigger conditions again as the on: section of the workflow and verify each event kind against the Forgejo Actions reference.
  - [ ] Decide where images and artifacts go: the package registry of STACKIT Git takes container images from any OCI client, or keep your own registry, and change the image names in the deploy steps.
- **Evidence** (validated against terraform-provider-google 8.4.0 (cloudbuild_trigger, cloudbuild_worker_pool); terraform-provider-stackit@0.121.0 (schema STACKIT provider schema 0.121.0: stackit_git is beta and creates the Git instance only; no pipeline, trigger or worker-pool resource); STACKIT Git management API v1beta (services/git/v1beta/git.json: instances, authentications, runner, users); docs.stackit.cloud developer-platform/git pages read 2026-11-05
): https://raw.githubusercontent.com/hashicorp/terraform-provider-google/v8.4.0/website/docs/r/cloudbuild_trigger.html.markdown · https://raw.githubusercontent.com/hashicorp/terraform-provider-google/v8.4.0/website/docs/r/cloudbuild_worker_pool.html.markdown · https://docs.stackit.cloud/products/developer-platform/git/ · https://docs.stackit.cloud/products/developer-platform/git/basics/stackit-pipelines/ · https://docs.stackit.cloud/products/developer-platform/git/getting-started/pipeline-runners/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/pipelines-custom-runner/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/pipeline-manual-approval/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/pipeline-stackit-compatibility/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/pipeline-github-compatibility/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/package-registry/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.121.0/docs/resources/git · https://github.com/stackitcloud/stackit-api-specifications/blob/main/services/git/v1beta/git.json

#### `google_cloudbuild_trigger.init`

- **Source:** `google_cloudbuild_trigger` — postdeployment.tf:144
- **Standing:** conditional — whether it exists is decided only when a plan runs; the class below is the one it would get, it is not counted in the totals and not automation-eligible.
- **Candidate target:** a workflow in STACKIT Git Pipelines (GitHub Actions syntax, STACKIT-managed or custom runners) or the customer's CI/CD (`stackit_git`)
- **Target maturity:** BETA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Automation cap:** a target resource is beta (the provider: "may be subject to breaking changes in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_git` (capability `devtools.git`).
- **GA target:** no GA target yet: stackit_git is beta in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** REDESIGN · **Confidence:** LOW · rule `gcp.cloudbuild/cicd-redesign`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (semantic project-residency, semantic build-identity, semantic log-destination, semantic deployment-artifact and 3 more); a point the scan could not establish
- **Why:** A Cloud Build trigger starts a build when a source event happens (a push or a pull request on GitHub, Bitbucket Server, a repository of the 2nd generation, Developer Connect or Cloud Source Repositories), when a Pub/Sub message arrives, when a webhook is called or when a person runs it. The build is a list of container steps (a build block, or a file in the repository) with substitutions, images and artifacts to push, secrets from Secret Manager, a service account, a log destination and optionally a manual approval. STACKIT has no trigger or build resource. The same delivery is a workflow of STACKIT Git Pipelines (workflows written for GitHub Actions; STACKIT-managed or custom runners; secrets from STACKIT Secrets Manager or the repository; a manual-approval action) or the customer's own CI/CD. Nothing is converted: the trigger conditions (branch and tag expressions, file filters, the event kind), the steps (a container step becomes a step or a job with a container), the secrets (created again, never copied), the service account (replaced by the credentials the workflow uses against STACKIT), the log destination and the approval are written again by a person. The pages read describe pipelines that run when changes are pushed; other events (pull requests, schedules, manual runs) are verified against the Forgejo Actions reference.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 2 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-SOURCE-PROJECT-MAPPING` (alias `convert:estate:source_project:SOURCE_PROJECT_MAPPING`): State where the units of each source project of the estate go · The source places its units in the project example-project, and in a project the scan cannot read for some units, and the source project is carried nowhere. A person maps the source projects by answering target.project.source_project for each: var.project_id, or the project of the unit's network (network-project). The answer records that mapping and changes nothing in the draft, which keeps its own project resolver.
  - decision `DEC-GEN-CONVERT-PROPOSED-ALTERNATIVE/google_cloudbuild_trigger.init` (alias `convert:google_cloudbuild_trigger.init:proposal:PROPOSED_ALTERNATIVE`): Decide whether the proposed STACKIT alternative replaces google_cloudbuild_trigger.init: read the module proposals/proposal_init, accept the difference and set its values, or design it another way · the target has no equal of this Cloud Build trigger: starts a build on a source event, a Pub/Sub message, a webhook or by hand, with its steps, substitutions, artifacts, secrets and optional approval: Nothing is converted. The same delivery is a workflow of STACKIT Git Pipelines (written for GitHub Actions; STACKIT-managed or custom runners; secrets from Secrets Manager or the repository; a manual-approval action) or the customer's own CI/CD. Trigger conditions, steps, secrets (created again, never copied), the service account (replaced by the credentials the workflow uses against STACKIT), the log destination and the approval are written again by a person. To decide: Which pipelines are still needed, where they run (STACKIT Git Pipelines or the customer's own CI/CD), how each trigger, step, secret and approval is written again, and who owns the workflow files.
- **Depends on:** `google_cloud_run_v2_job.migrate`, `google_cloud_run_v2_service.server`, `google_firebase_hosting_site.client`, `google_pubsub_topic.faux`, `google_secret_manager_secret.django_admin_password`, `google_secret_manager_secret.django_settings`, `google_service_account.automation`, `google_service_account.client`, `google_service_account.init`, `google_sql_database_instance.postgres`
- **INFO** (cloudbuild-source-event): This trigger starts its builds on a Pub/Sub message. The replacement workflow lists the events that start it in its own on: section; the pages of STACKIT read describe pipelines that run whenever changes are pushed to a repository, so a pull request, a schedule or a manual start is verified by a person against the Forgejo Actions reference.
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (linked-dependency-unread): This unit names google_cloud_run_v2_job.migrate (google_cloud_run_v2_job), which the draft carries. The unit is left for a redesign and the converter writes no block for it, so the reference is not written into the draft. A person re-makes the reference in the redesign of this unit; it is part of that redesign, not a decision of its own.
- **WARNING** (linked-dependency-unread): This unit names google_cloud_run_v2_service.server (google_cloud_run_v2_service), which the draft carries. The unit is left for a redesign and the converter writes no block for it, so the reference is not written into the draft. A person re-makes the reference in the redesign of this unit; it is part of that redesign, not a decision of its own.
- **WARNING** (linked-dependency-unread): This unit names google_firebase_hosting_site.client (google_firebase_hosting_site), whose own decision the target does not carry (it is REDESIGN), and the semantic contract of google_cloudbuild_trigger does not read google_firebase_hosting_site, so what the reference becomes is not assessed.
- **WARNING** (linked-dependency-unread): This unit names google_sql_database_instance.postgres (google_sql_database_instance), which the draft carries. The unit is left for a redesign and the converter writes no block for it, so the reference is not written into the draft. A person re-makes the reference in the redesign of this unit; it is part of that redesign, not a decision of its own.
- **Critical semantics left to you to decide or accept (6):** build-identity, dep-references, deployment-artifact, entry-point, log-destination, project-residency (**not automation-eligible**: no property the unit sets is read by dep-references, linked-dependency:google_firebase_hosting_site)
- **5 critical setting(s) left to you** (not drafted — REDESIGN) — **not automation-eligible**:
  - identity access (1; REVIEW 1): `service_account`
  - audit logging (1; REVIEW 1): `build.options.logging`
  - residency compliance (1; REVIEW 1): `location`
  - workload compatibility (2; REVIEW 2): `build.step.name`, `build.step.script`
- **Why those are open, and what closes them:**
  - `project-residency`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. Project and Cloud Build location are data-residency/project-boundary facts with no STACKIT CI/CD resource to remap them onto -- REVIEW. Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `build-identity`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The service account the build (or the Pub/Sub push notification) runs as; STACKIT Git Pipelines has its own, differently-shaped identity model -- REVIEW. Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `log-destination`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The setting states where/whether build logs are captured or exposed back to GitHub; STACKIT Git Pipelines' own logging model is different -- REVIEW. Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `deployment-artifact`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_cloudbuild_trigger.build.step.name, artifact or image reference (workload compatibility: a setting that binds the code to its runtime stays CRITICAL). Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `entry-point`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_cloudbuild_trigger.build.step.entrypoint, build.step.script, build.step.args, entry point (workload compatibility: a setting that binds the code to its runtime stays CRITICAL). The unit names google_firebase_hosting_site.client (google_firebase_hosting_site) through this setting (the target does not carry it: it is REDESIGN), so what the reference becomes is part of this setting. Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `dep-references`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_cloudbuild_trigger and google_cloudbuild_worker_pool names other units or resources (google_cloudbuild_bitbucket_server_config, google_cloudbuild_worker_pool, google_cloudbuildv2_repository, google_compute_global_address, google_compute_network, google_developer_connect_git_repository_link, google_pubsub_topic, google_secret_manager_secret, google_secret_manager_secret_version, google_service_account, google_sourcerepo_repository, google_storage_bucket). A person confirms how the replacement carries the relation between this unit and the units it names, or accepts the difference. Closes when: A person confirms how the replacement carries the relation, or accepts the difference.
- **Review:**
  - [ ] Write the workflow in the repository: one job (or step) per build step, with the same container images or their STACKIT equivalents.
  - [ ] Recreate every secret the build reads in STACKIT Secrets Manager (read with the vault action) or as a repository secret; the values of the source are never copied.
  - [ ] Write the trigger conditions again as the on: section of the workflow and verify each event kind against the Forgejo Actions reference.
  - [ ] Decide where images and artifacts go: the package registry of STACKIT Git takes container images from any OCI client, or keep your own registry, and change the image names in the deploy steps.
- **Evidence** (validated against terraform-provider-google 8.4.0 (cloudbuild_trigger, cloudbuild_worker_pool); terraform-provider-stackit@0.121.0 (schema STACKIT provider schema 0.121.0: stackit_git is beta and creates the Git instance only; no pipeline, trigger or worker-pool resource); STACKIT Git management API v1beta (services/git/v1beta/git.json: instances, authentications, runner, users); docs.stackit.cloud developer-platform/git pages read 2026-11-05
): https://raw.githubusercontent.com/hashicorp/terraform-provider-google/v8.4.0/website/docs/r/cloudbuild_trigger.html.markdown · https://raw.githubusercontent.com/hashicorp/terraform-provider-google/v8.4.0/website/docs/r/cloudbuild_worker_pool.html.markdown · https://docs.stackit.cloud/products/developer-platform/git/ · https://docs.stackit.cloud/products/developer-platform/git/basics/stackit-pipelines/ · https://docs.stackit.cloud/products/developer-platform/git/getting-started/pipeline-runners/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/pipelines-custom-runner/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/pipeline-manual-approval/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/pipeline-stackit-compatibility/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/pipeline-github-compatibility/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/package-registry/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.121.0/docs/resources/git · https://github.com/stackitcloud/stackit-api-specifications/blob/main/services/git/v1beta/git.json

#### `google_cloudbuild_trigger.placeholder`

- **Source:** `google_cloudbuild_trigger` — postdeployment.tf:87
- **Standing:** conditional — whether it exists is decided only when a plan runs; the class below is the one it would get, it is not counted in the totals and not automation-eligible.
- **Candidate target:** a workflow in STACKIT Git Pipelines (GitHub Actions syntax, STACKIT-managed or custom runners) or the customer's CI/CD (`stackit_git`)
- **Target maturity:** BETA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Automation cap:** a target resource is beta (the provider: "may be subject to breaking changes in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_git` (capability `devtools.git`).
- **GA target:** no GA target yet: stackit_git is beta in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** REDESIGN · **Confidence:** LOW · rule `gcp.cloudbuild/cicd-redesign`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (semantic project-residency, semantic build-identity, semantic log-destination, semantic deployment-artifact and 2 more); a point the scan could not establish
- **Why:** A Cloud Build trigger starts a build when a source event happens (a push or a pull request on GitHub, Bitbucket Server, a repository of the 2nd generation, Developer Connect or Cloud Source Repositories), when a Pub/Sub message arrives, when a webhook is called or when a person runs it. The build is a list of container steps (a build block, or a file in the repository) with substitutions, images and artifacts to push, secrets from Secret Manager, a service account, a log destination and optionally a manual approval. STACKIT has no trigger or build resource. The same delivery is a workflow of STACKIT Git Pipelines (workflows written for GitHub Actions; STACKIT-managed or custom runners; secrets from STACKIT Secrets Manager or the repository; a manual-approval action) or the customer's own CI/CD. Nothing is converted: the trigger conditions (branch and tag expressions, file filters, the event kind), the steps (a container step becomes a step or a job with a container), the secrets (created again, never copied), the service account (replaced by the credentials the workflow uses against STACKIT), the log destination and the approval are written again by a person. The pages read describe pipelines that run when changes are pushed; other events (pull requests, schedules, manual runs) are verified against the Forgejo Actions reference.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 2 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-SOURCE-PROJECT-MAPPING` (alias `convert:estate:source_project:SOURCE_PROJECT_MAPPING`): State where the units of each source project of the estate go · The source places its units in the project example-project, and in a project the scan cannot read for some units, and the source project is carried nowhere. A person maps the source projects by answering target.project.source_project for each: var.project_id, or the project of the unit's network (network-project). The answer records that mapping and changes nothing in the draft, which keeps its own project resolver.
  - decision `DEC-GEN-CONVERT-PROPOSED-ALTERNATIVE/google_cloudbuild_trigger.placeholder` (alias `convert:google_cloudbuild_trigger.placeholder:proposal:PROPOSED_ALTERNATIVE`): Decide whether the proposed STACKIT alternative replaces google_cloudbuild_trigger.placeholder: read the module proposals/proposal_placeholder, accept the difference and set its values, or design it another way · the target has no equal of this Cloud Build trigger: starts a build on a source event, a Pub/Sub message, a webhook or by hand, with its steps, substitutions, artifacts, secrets and optional approval: Nothing is converted. The same delivery is a workflow of STACKIT Git Pipelines (written for GitHub Actions; STACKIT-managed or custom runners; secrets from Secrets Manager or the repository; a manual-approval action) or the customer's own CI/CD. Trigger conditions, steps, secrets (created again, never copied), the service account (replaced by the credentials the workflow uses against STACKIT), the log destination and the approval are written again by a person. To decide: Which pipelines are still needed, where they run (STACKIT Git Pipelines or the customer's own CI/CD), how each trigger, step, secret and approval is written again, and who owns the workflow files.
- **Depends on:** `google_firebase_hosting_site.client`, `google_pubsub_topic.faux`, `google_service_account.init`
- **INFO** (cloudbuild-source-event): This trigger starts its builds on a Pub/Sub message. The replacement workflow lists the events that start it in its own on: section; the pages of STACKIT read describe pipelines that run whenever changes are pushed to a repository, so a pull request, a schedule or a manual start is verified by a person against the Forgejo Actions reference.
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (linked-dependency-unread): This unit names google_firebase_hosting_site.client (google_firebase_hosting_site), whose own decision the target does not carry (it is REDESIGN), and the semantic contract of google_cloudbuild_trigger does not read google_firebase_hosting_site, so what the reference becomes is not assessed.
- **Critical semantics left to you to decide or accept (6):** build-identity, dep-references, deployment-artifact, linked-dependency:google_firebase_hosting_site, log-destination, project-residency (**not automation-eligible**: no property the unit sets is read by dep-references, linked-dependency:google_firebase_hosting_site)
- **4 critical setting(s) left to you** (not drafted — REDESIGN) — **not automation-eligible**:
  - identity access (1; REVIEW 1): `service_account`
  - audit logging (1; REVIEW 1): `build.options.logging`
  - residency compliance (1; REVIEW 1): `location`
  - workload compatibility (1; REVIEW 1): `build.step.name`
- **Why those are open, and what closes them:**
  - `project-residency`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. Project and Cloud Build location are data-residency/project-boundary facts with no STACKIT CI/CD resource to remap them onto -- REVIEW. Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `build-identity`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The service account the build (or the Pub/Sub push notification) runs as; STACKIT Git Pipelines has its own, differently-shaped identity model -- REVIEW. Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `log-destination`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The setting states where/whether build logs are captured or exposed back to GitHub; STACKIT Git Pipelines' own logging model is different -- REVIEW. Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `deployment-artifact`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_cloudbuild_trigger.build.step.name, artifact or image reference (workload compatibility: a setting that binds the code to its runtime stays CRITICAL). Closes when: A person decides the setting with what replaces the unit once the architect has chosen it, or the knowledge base gains a rule that decides this setting.
  - `dep-references`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_cloudbuild_trigger and google_cloudbuild_worker_pool names other units or resources (google_cloudbuild_bitbucket_server_config, google_cloudbuild_worker_pool, google_cloudbuildv2_repository, google_compute_global_address, google_compute_network, google_developer_connect_git_repository_link, google_pubsub_topic, google_secret_manager_secret, google_secret_manager_secret_version, google_service_account, google_sourcerepo_repository, google_storage_bucket). A person confirms how the replacement carries the relation between this unit and the units it names, or accepts the difference. Closes when: A person confirms how the replacement carries the relation, or accepts the difference.
  - `linked-dependency:google_firebase_hosting_site`: This unit names a resource of the type google_firebase_hosting_site (by an attribute that configures it) and the target does not carry that resource as a mapped unit (it is redesigned, blocked, left for review or has no draft block of its own), and no semantic of this unit's contract reads that type: what the reference becomes on the target is not assessed. Closes when: The contract of this unit gains a semantic that reads google_firebase_hosting_site (and lists it as carried), or a person decides what the reference to the resource becomes.
- **Review:**
  - [ ] Write the workflow in the repository: one job (or step) per build step, with the same container images or their STACKIT equivalents.
  - [ ] Recreate every secret the build reads in STACKIT Secrets Manager (read with the vault action) or as a repository secret; the values of the source are never copied.
  - [ ] Write the trigger conditions again as the on: section of the workflow and verify each event kind against the Forgejo Actions reference.
  - [ ] Decide where images and artifacts go: the package registry of STACKIT Git takes container images from any OCI client, or keep your own registry, and change the image names in the deploy steps.
- **Evidence** (validated against terraform-provider-google 8.4.0 (cloudbuild_trigger, cloudbuild_worker_pool); terraform-provider-stackit@0.121.0 (schema STACKIT provider schema 0.121.0: stackit_git is beta and creates the Git instance only; no pipeline, trigger or worker-pool resource); STACKIT Git management API v1beta (services/git/v1beta/git.json: instances, authentications, runner, users); docs.stackit.cloud developer-platform/git pages read 2026-11-05
): https://raw.githubusercontent.com/hashicorp/terraform-provider-google/v8.4.0/website/docs/r/cloudbuild_trigger.html.markdown · https://raw.githubusercontent.com/hashicorp/terraform-provider-google/v8.4.0/website/docs/r/cloudbuild_worker_pool.html.markdown · https://docs.stackit.cloud/products/developer-platform/git/ · https://docs.stackit.cloud/products/developer-platform/git/basics/stackit-pipelines/ · https://docs.stackit.cloud/products/developer-platform/git/getting-started/pipeline-runners/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/pipelines-custom-runner/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/pipeline-manual-approval/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/pipeline-stackit-compatibility/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/pipeline-github-compatibility/ · https://docs.stackit.cloud/products/developer-platform/git/how-tos/package-registry/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.121.0/docs/resources/git · https://github.com/stackitcloud/stackit-api-specifications/blob/main/services/git/v1beta/git.json

### Data

#### `google_sql_database_instance.postgres`

- **Source:** `google_sql_database_instance` — database.tf:25
- **Candidate target:** STACKIT PostgreSQL Flex (`stackit_postgresflex_instance`, `stackit_postgresflex_database`, `stackit_postgresflex_user`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Classification:** REPLATFORM · **Confidence:** MEDIUM · rule `gcp.sql_instance/sql-postgres`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (semantic database-users, semantic user-and-database-settings, semantic region-residency, semantic project-scope and 3 more); a point the scan could not establish
- **Why:** Managed PostgreSQL to managed PostgreSQL: data moves with pg_dump/pg_restore or logical replication, the tier becomes a Flex flavor, and authorized networks / private IP become the instance ACL.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 3 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-SOURCE-REGION-MAPPING` (alias `convert:estate:source_location:SOURCE_REGION_MAPPING`): Map each source location of the estate to a STACKIT region · The source places its units in a location the scan cannot read (the value comes from an input a plan can change, or the source does not state it). No mapping between Google and STACKIT regions is evidenced, so the region the draft builds in is not shown to hold the residency of a source location: a person states it once for the estate, by answering target.region.source_location for each location.
  - decision `DEC-GEN-CONVERT-SOURCE-PROJECT-MAPPING` (alias `convert:estate:source_project:SOURCE_PROJECT_MAPPING`): State where the units of each source project of the estate go · The source places its units in the project example-project, and in a project the scan cannot read for some units, and the source project is carried nowhere. A person maps the source projects by answering target.project.source_project for each: var.project_id, or the project of the unit's network (network-project). The answer records that mapping and changes nothing in the draft, which keeps its own project resolver.
  - decision `DEC-GEN-CONVERT-DATA-MOVEMENT` (alias `convert:google_sql_database_instance.postgres:data:DATA_MOVEMENT`): Choose how the data of google_sql_database_instance.postgres moves from google_sql_database_instance to PostgreSQL Flex (stackit_postgresflex_instance.postgres): a dump restored inside the write freeze, the engine's logical replication, or a tool of your own · the plan defines both methods of the engine (a dump restored inside the write freeze, and a logical replication that follows the changes until the freeze) and keeps them open: which one applies depends on the size of the data, the write rate and the downtime the business accepts, and the source states none of them; the steps of the methods wait for the answer
- **Includes:** `google_sql_database.database`, `google_sql_user.django`
- **INFO** (sql-pg-version-supported): The PostgreSQL major version is one PostgreSQL Flex offers (14–18).
- **INFO** (sql-user-not-generated): Not verifiable statically (name of facet `google_sql_user.django` not visible): A database user is an IAM user (or its name or type is not visible statically); the draft generates password users only — create the others as password users after review.
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (6):** database-users, user-and-database-settings, region-residency, project-scope, tc-name, tcf-sql-database--name
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-DATA-MOVEMENT` (alias `convert:google_sql_database_instance.postgres:data:DATA_MOVEMENT`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Property accounting:** 12 of 12 meaningful properties accounted
- **8 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (2; open 1 · REVIEW 1): `project`, `google_sql_user.django.name` — NOT CARRIED (google_sql_user.django): name — a user name is not visible statically: create that user with stackit_postgresflex_user.
  - deletion protection (2; REVIEW 2): `google_sql_database.database.deletion_policy`, `google_sql_user.django.deletion_policy` — NOT CARRIED (google_sql_database.database): deletion_policy — stackit_postgresflex_database is deleted directly (pinned provider): ABANDON (keep the Cloud SQL database, drop it from state only) has no counterpart.
  - secret handling (1; REVIEW 1): `google_sql_user.django.password` — NOT CARRIED (google_sql_user.django): password — the source password is not copied: STACKIT generates the user's password (stackit_postgresflex_user.password is computed, pinned provider) — hand the new one to the application.
  - residency compliance (1; open 1): `region`
  - workload compatibility (2; REVIEW 2): `name`, `google_sql_database.database.name` — NOT CARRIED (google_sql_database.database): name — a database name (or the number of databases) is not visible statically: create that database with stackit_postgresflex_database.
- **Why those are open, and what closes them:**
  - `database-users`: A check of the knowledge base (sql user not generated) needs a value the scan cannot read statically, so it could not decide. A built-in user of a PostgreSQL instance becomes a stackit_postgresflex_user with the same username (pinned provider) — TRANSFORMED. IAM users (and a name or type not visible statically) are not generated — REVIEW (check sql-user-not-generated); users of the other engines are named NOT CARRIED — REVIEW. Closes when: A literal value or a resolved reference in the source lets the check decide, or a person verifies the value.
  - `user-and-database-settings`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The source password is not copied (STACKIT generates it: stackit_postgresflex_user.password is computed), a host restriction and ABANDON deletion policies have no counterpart (pinned provider) — the draft names them NOT CARRIED — REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `region-residency`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The region of the instance (google 8.4.0 `region`; unset means the provider's region). A person confirms the region — REVIEW (critical, the value is not verified against the target). Closes when: A person confirms the STACKIT region of the instance (and of a read replica, decided with its primary) holds the residency the source region gave.
  - `project-scope`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The project of the instance (google 8.4.0 `project`: "The ID of the project in which the resource belongs. If it is not provided, the provider project is used"). A STACKIT project is the scope for ownership, resource consumption and access control (docs.stackit.cloud/platform/resource-manager/basics/projects/): whether the database's source project becomes the project of the rest of the estate is a design decision no rule evidences — a person confirms it — REVIEW (critical). Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `tc-name`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_sql_database_instance.name: The instance's name/label; does not itself grant access, encrypt data, or control backups/availability/residency. Closes when: A person confirms the instance name the STACKIT database carries against what refers to the source instance name, or accepts the new name.
  - `tcf-sql-database--name`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_sql_database.name (a facet of the unit): The literal database name; determines the connection target's label but does not itself grant or restrict access, encrypt data, or affect backups/availability/residency. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs postgresql-flex/mariadb/sqlserver-flex 2026-09-23; sql-deletion-protection re-checked 2026-10-07 against provider schema 0.117.0 (stackit_postgresflex_instance / stackit_sqlserverflex_instance: no protection attribute), the postgres-flex / sqlserverflex v3 API specs (POST .../protections isDeletable) and the PostgreSQL Flex instance-protection docs; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/databases/postgresql-flex/ · https://docs.stackit.cloud/products/databases/mariadb/ · https://docs.stackit.cloud/products/databases/sqlserver-flex/reference/supported-and-unsupported-features-in-sqlserver-flex/

### Identity

#### `google_service_account.automation`

- **Source:** `google_service_account` — iam.tf:54
- **Candidate target:** STACKIT service account (`stackit_service_account`, `stackit_authorization_project_role_assignment`, `stackit_authorization_folder_role_assignment`, `stackit_authorization_organization_role_assignment`, `stackit_authorization_service_account_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_folder_role_assignment` (capability `identity.role-assignment`), `stackit_authorization_organization_role_assignment` (capability `identity.role-assignment`), `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`), `stackit_authorization_service_account_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_folder_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_authorization_organization_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_authorization_service_account_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `gcp.service_account/service-account`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic role-bindings, semantic account-name); a point the scan could not establish
- **Why:** A Google service account becomes a STACKIT service account named after its account ID (shortened to the STACKIT name rules, so its e-mail address changes and every reference to it is updated). What the account may do is what the IAM resources of the estate grant it, and the draft carries that where it can show the mapping: a grant to the account on a project, a folder or an organisation becomes a STACKIT role assignment of the account. The role is written as it is only where the Google role has a STACKIT role with the same permissions or fewer on a project; every other role is an input without a default that names the candidates and how they differ, because a wider role is never a default. A grant that lets another account act as this one becomes an Act-As assignment. Grants that cannot be written are listed in the draft with the reason: a condition (a STACKIT role assignment has none), a policy document, a repeated grant, a role or a member that is not visible statically, and a member that is a person, a group or the identity of a Kubernetes workload. An additive grant (a member) adds one member and removes none, as a role assignment does; a binding or a policy removes every member of its role that it does not list, a role assignment never removes anyone, and the draft marks each such grant. The workloads that ran as the account are not attached to it by this block; workloads that got credentials from the metadata server or GKE Workload Identity need explicit STACKIT credentials or a federated identity. Keys are never carried.
- **INFO** (sa-account-id-not-visible): The account ID is not visible statically; the STACKIT account is named after the source address. — a variable's default, not a fact
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Inherited placement:** provider configuration `google`, source region `us-central1`.
- **Critical semantics left to you to decide or accept (2):** role-bindings, account-name (**not automation-eligible**: no property the unit sets is read by role-bindings)
- **Property accounting:** 2 of 2 meaningful properties accounted
- **1 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (1; REVIEW 1): `account_id` — NOT CARRIED (google_service_account.automation): account_id — the account ID is not visible statically, or the account is declared several times: the STACKIT account is named after the source address.
- **Why those are open, and what closes them:**
  - `role-bindings`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The grants of the estate that name the account: a grant on a project, a folder or an organisation is written as a STACKIT role assignment of the account when its role and members are visible statically and it has no condition, and a grant that lets another account act as it is written as an Act-As assignment. A Google role is written as a STACKIT role only where the mapping shows the STACKIT role holds the same permissions or fewer on a project; every other role is an input that names the candidates, and a person confirms each. A binding or a policy is authoritative (it removes the members of its role that it does not list) and a role assignment only adds, which the draft says on each: members that hold the role outside the configuration keep it on STACKIT until a person removes them. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `account-name`: A check of the knowledge base (sa account id not visible) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The account ID becomes the stackit_service_account name (shortened to the STACKIT name rules; pinned provider) — TRANSFORMED; the e-mail address changes. An ID not visible statically (or a repeated account) is named NOT CARRIED — REVIEW (check sa-account-id-not-visible). Closes when: A person decides what this finding asks, and records the evidence or the decision. The finding says: The account ID is not visible statically; the STACKIT account is named after the source address. — a variable's default, not a fact.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

#### `google_service_account.client`

- **Source:** `google_service_account` — iam.tf:48
- **Candidate target:** STACKIT service account (`stackit_service_account`, `stackit_authorization_project_role_assignment`, `stackit_authorization_folder_role_assignment`, `stackit_authorization_organization_role_assignment`, `stackit_authorization_service_account_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_folder_role_assignment` (capability `identity.role-assignment`), `stackit_authorization_organization_role_assignment` (capability `identity.role-assignment`), `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`), `stackit_authorization_service_account_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_folder_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_authorization_organization_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_authorization_service_account_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `gcp.service_account/service-account`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic role-bindings, semantic account-name); a point the scan could not establish
- **Why:** A Google service account becomes a STACKIT service account named after its account ID (shortened to the STACKIT name rules, so its e-mail address changes and every reference to it is updated). What the account may do is what the IAM resources of the estate grant it, and the draft carries that where it can show the mapping: a grant to the account on a project, a folder or an organisation becomes a STACKIT role assignment of the account. The role is written as it is only where the Google role has a STACKIT role with the same permissions or fewer on a project; every other role is an input without a default that names the candidates and how they differ, because a wider role is never a default. A grant that lets another account act as this one becomes an Act-As assignment. Grants that cannot be written are listed in the draft with the reason: a condition (a STACKIT role assignment has none), a policy document, a repeated grant, a role or a member that is not visible statically, and a member that is a person, a group or the identity of a Kubernetes workload. An additive grant (a member) adds one member and removes none, as a role assignment does; a binding or a policy removes every member of its role that it does not list, a role assignment never removes anyone, and the draft marks each such grant. The workloads that ran as the account are not attached to it by this block; workloads that got credentials from the metadata server or GKE Workload Identity need explicit STACKIT credentials or a federated identity. Keys are never carried.
- **INFO** (sa-account-id-not-visible): The account ID is not visible statically; the STACKIT account is named after the source address. — a variable's default, not a fact
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Inherited placement:** provider configuration `google`, source region `us-central1`.
- **Critical semantics left to you to decide or accept (2):** role-bindings, account-name (**not automation-eligible**: no property the unit sets is read by role-bindings)
- **Property accounting:** 2 of 2 meaningful properties accounted
- **1 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (1; REVIEW 1): `account_id` — NOT CARRIED (google_service_account.client): account_id — the account ID is not visible statically, or the account is declared several times: the STACKIT account is named after the source address.
- **Why those are open, and what closes them:**
  - `role-bindings`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The grants of the estate that name the account: a grant on a project, a folder or an organisation is written as a STACKIT role assignment of the account when its role and members are visible statically and it has no condition, and a grant that lets another account act as it is written as an Act-As assignment. A Google role is written as a STACKIT role only where the mapping shows the STACKIT role holds the same permissions or fewer on a project; every other role is an input that names the candidates, and a person confirms each. A binding or a policy is authoritative (it removes the members of its role that it does not list) and a role assignment only adds, which the draft says on each: members that hold the role outside the configuration keep it on STACKIT until a person removes them. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `account-name`: A check of the knowledge base (sa account id not visible) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The account ID becomes the stackit_service_account name (shortened to the STACKIT name rules; pinned provider) — TRANSFORMED; the e-mail address changes. An ID not visible statically (or a repeated account) is named NOT CARRIED — REVIEW (check sa-account-id-not-visible). Closes when: A person decides what this finding asks, and records the evidence or the decision. The finding says: The account ID is not visible statically; the STACKIT account is named after the source address. — a variable's default, not a fact.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

#### `google_service_account.server`

- **Source:** `google_service_account` — iam.tf:42
- **Candidate target:** STACKIT service account (`stackit_service_account`, `stackit_authorization_project_role_assignment`, `stackit_authorization_folder_role_assignment`, `stackit_authorization_organization_role_assignment`, `stackit_authorization_service_account_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_folder_role_assignment` (capability `identity.role-assignment`), `stackit_authorization_organization_role_assignment` (capability `identity.role-assignment`), `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`), `stackit_authorization_service_account_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_folder_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_authorization_organization_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_authorization_service_account_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `gcp.service_account/service-account`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic role-bindings, semantic account-name); a point the scan could not establish
- **Why:** A Google service account becomes a STACKIT service account named after its account ID (shortened to the STACKIT name rules, so its e-mail address changes and every reference to it is updated). What the account may do is what the IAM resources of the estate grant it, and the draft carries that where it can show the mapping: a grant to the account on a project, a folder or an organisation becomes a STACKIT role assignment of the account. The role is written as it is only where the Google role has a STACKIT role with the same permissions or fewer on a project; every other role is an input without a default that names the candidates and how they differ, because a wider role is never a default. A grant that lets another account act as this one becomes an Act-As assignment. Grants that cannot be written are listed in the draft with the reason: a condition (a STACKIT role assignment has none), a policy document, a repeated grant, a role or a member that is not visible statically, and a member that is a person, a group or the identity of a Kubernetes workload. An additive grant (a member) adds one member and removes none, as a role assignment does; a binding or a policy removes every member of its role that it does not list, a role assignment never removes anyone, and the draft marks each such grant. The workloads that ran as the account are not attached to it by this block; workloads that got credentials from the metadata server or GKE Workload Identity need explicit STACKIT credentials or a federated identity. Keys are never carried.
- **INFO** (sa-account-id-not-visible): The account ID is not visible statically; the STACKIT account is named after the source address. — a variable's default, not a fact
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Inherited placement:** provider configuration `google`, source region `us-central1`.
- **Critical semantics left to you to decide or accept (2):** role-bindings, account-name (**not automation-eligible**: no property the unit sets is read by role-bindings)
- **Property accounting:** 2 of 2 meaningful properties accounted
- **1 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (1; REVIEW 1): `account_id` — NOT CARRIED (google_service_account.server): account_id — the account ID is not visible statically, or the account is declared several times: the STACKIT account is named after the source address.
- **Why those are open, and what closes them:**
  - `role-bindings`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The grants of the estate that name the account: a grant on a project, a folder or an organisation is written as a STACKIT role assignment of the account when its role and members are visible statically and it has no condition, and a grant that lets another account act as it is written as an Act-As assignment. A Google role is written as a STACKIT role only where the mapping shows the STACKIT role holds the same permissions or fewer on a project; every other role is an input that names the candidates, and a person confirms each. A binding or a policy is authoritative (it removes the members of its role that it does not list) and a role assignment only adds, which the draft says on each: members that hold the role outside the configuration keep it on STACKIT until a person removes them. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `account-name`: A check of the knowledge base (sa account id not visible) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The account ID becomes the stackit_service_account name (shortened to the STACKIT name rules; pinned provider) — TRANSFORMED; the e-mail address changes. An ID not visible statically (or a repeated account) is named NOT CARRIED — REVIEW (check sa-account-id-not-visible). Closes when: A person decides what this finding asks, and records the evidence or the decision. The finding says: The account ID is not visible statically; the STACKIT account is named after the source address. — a variable's default, not a fact.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

#### `google_secret_manager_secret.django_admin_password`

- **Source:** `google_secret_manager_secret` — secrets.tf:25
- **Candidate target:** STACKIT Secrets Manager (`stackit_secretsmanager_instance`, `stackit_secretsmanager_user`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `gcp.secret/secret`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (check secret-iam-access, semantic secret-value, semantic secret-settings, semantic tcr-secret-id); a point the scan could not establish
- **Why:** Secrets move to STACKIT Secrets Manager (a Vault-compatible KV store). Applications switch from the Secret Manager client to a Vault client or to injection by the platform (e.g. External Secrets Operator on SKE); IAM accessors become Secrets Manager users (read-only or read-write for the whole instance) or, narrower and experimental, role bindings on a secret group.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 2 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-API-OPT-IN/google_secret_manager_secret.django_admin_password` (alias `convert:api:secrets-manager-vault:v1:unknown:API_OPT_IN`): Allow calls of the Secrets Manager Vault-compatible API, whose maturity is not established, for this migration (the API may change or vanish)? Accept: the calls of the Secrets Manager Vault-compatible API (WriteSecret) are carried out for google_secret_manager_secret.django_admin_password, google_secret_manager_secret.django_settings. Refuse: no call is made, a refusal selects no other path (the draft holds no other carrier of what the calls set), and what they set stays open for google_secret_manager_secret.django_admin_password, google_secret_manager_secret.django_settings. · the Secrets Manager Vault-compatible API is of a maturity that is not established (its documentation states no release status and its product documentation does not establish it as generally available): the execution plan executes no call of an API that is not generally available without an explicit opt-in, so the calls of it and the steps of its path for google_secret_manager_secret.django_admin_password, google_secret_manager_secret.django_settings wait for this decision; the draft's own blocks do not
  - decision `DEC-GEN-CONVERT-PROPOSED-ALTERNATIVE/google_secret_manager_secret_iam_binding.django_admin_password` (alias `convert:google_secret_manager_secret_iam_binding.django_admin_password:proposal:PROPOSED_ALTERNATIVE`): Decide whether the proposed STACKIT alternative replaces google_secret_manager_secret_iam_binding.django_admin_password: read the module proposals/proposal_django_admin_password, accept the difference and set its values, or design it another way · the target has no equal of this the members of one role on the Secret Manager secret: A STACKIT role assignment is not a grant on the Secret Manager secret. It gives one user, group or service account one STACKIT role on a whole project, folder or organisation. The role is a set of STACKIT permissions, not the Google role, and no table maps one to the other. It has no condition and no public member, so what the grant gave to a Google group, a domain, a federated identity or everyone is named again, and the access reaches more than the Secret Manager secret. A binding on a secret group applies to every secret in the group, so it is wider than a grant on one secret unless the secret has a group of its own, and its roles are Secrets Manager roles. The binding was authoritative for its role: STACKIT role assignments are additive, so a person who holds the role through another assignment keeps it, and removing such people is a step of a person. To decide: Which STACKIT role, on which project, folder or organisation, gives the same people the access they need on the Secret Manager secret, knowing it covers everything in that scope; which STACKIT users, groups or service accounts take the place of Google groups, domains, federated identities and a public member; and whether the grant ends with the Secret Manager secret when it has no replacement. For secrets: which secret group holds the secret, who else shares that group, and which Secrets Manager role and subject take the grant. Whether people who hold the role through another assignment keep it. The draft of google_secret_manager_secret.django_admin_password stands as it is: this answer decides the module and nothing of that draft.
- **Includes:** `google_secret_manager_secret_iam_binding.django_admin_password`, `google_secret_manager_secret_version.django_admin_password`
- **Depends on:** `google_service_account.automation`
- **WARNING** (secret-iam-access): The secret has grants for individual principals. Access on STACKIT Secrets Manager is coarser than a Secret Manager grant: a Secrets Manager user is read-only or read-write for the whole secrets engine of its instance, with no scope to one secret or path. Narrower access exists only as role bindings on the instance or on a secret group (a named list of secrets) in the alpha API of the service, and the pinned provider offers them as resources of its experimental IAM feature (stackit_secretsmanager_instance_role_binding_v1 and stackit_secretsmanager_secret_group_role_binding_v1), which its documentation says may change or be removed; the specification does not list the roles a secret group accepts. A grant of one Google principal on one secret therefore cannot be carried one to one: decide per principal whether it gets a user of the whole instance, a role binding on a secret group of the secrets it may read, or a separate Secrets Manager instance.
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Inherited placement:** provider configuration `google`, source region `us-central1`.
- **Critical semantics left to you to decide or accept (3):** secret-value, secret-settings, tcr-secret-id
- **Property accounting:** 5 of 5 meaningful properties accounted
- **5 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (2; REVIEW 2): `google_secret_manager_secret_iam_binding.django_admin_password.members`, `google_secret_manager_secret_iam_binding.django_admin_password.role` — NOT CARRIED (google_secret_manager_secret_iam_binding.django_admin_password): members, role = roles/secretmanager.secretAccessor — the API step API/secrets-manager-vault/WriteSecret/google_secret_manager_secret.django_admin_password writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
  - secret handling (2; REVIEW 2): `secret_id`, `google_secret_manager_secret_version.django_admin_password.secret_data` — NOT CARRIED (google_secret_manager_secret.django_admin_password): replication, secret_id — the API step API/secrets-manager-vault/WriteSecret/google_secret_manager_secret.django_admin_password writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
  - residency compliance (1; REVIEW 1): `replication.user_managed.replicas.location` — NOT CARRIED (google_secret_manager_secret.django_admin_password): replication, secret_id — the API step API/secrets-manager-vault/WriteSecret/google_secret_manager_secret.django_admin_password writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
- **Why those are open, and what closes them:**
  - `secret-value`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_secret_manager_secret_version.secret_data: the value of the secret. StackToIT never reads it and never writes it into the draft; the API step of the secret writes the document the customer supplies. Closes when: A person decides where the value comes from, supplies the document and the step has run.
  - `secret-settings`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The settings of the secret beside its value (secret-value): STACKIT replicates it itself (no replica locations or per-replica keys), tags and version states have no counterpart, and IAM members and policy map to Secrets Manager users (read-only or read-write for a whole instance) or to experimental role bindings on a secret group — REVIEW. Closes when: A person recreates the secret in the Secrets Manager instance, since its data is not written into the draft, and decides for each IAM member whether it gets a user of the whole instance, a role binding on a secret group, or a separate instance.
  - `tcr-secret-id`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_secret_manager_secret.secret_id: The secret's own resource identifier; access to the secret's value is controlled by IAM bindings and replication/encryption settings, not by the id string itself. Closes when: A person confirms the secret name in STACKIT Secrets Manager against what refers to the source secret ID, or accepts the new name.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs security/secrets-manager 2026-09-23; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/security/secrets-manager/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/secretsmanager_instance

#### `google_secret_manager_secret.django_settings`

- **Source:** `google_secret_manager_secret` — secrets.tf:56
- **Candidate target:** STACKIT Secrets Manager (`stackit_secretsmanager_instance`, `stackit_secretsmanager_user`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `gcp.secret/secret`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (check secret-iam-access, semantic secret-value, semantic secret-settings, semantic tcr-secret-id); a point the scan could not establish
- **Why:** Secrets move to STACKIT Secrets Manager (a Vault-compatible KV store). Applications switch from the Secret Manager client to a Vault client or to injection by the platform (e.g. External Secrets Operator on SKE); IAM accessors become Secrets Manager users (read-only or read-write for the whole instance) or, narrower and experimental, role bindings on a secret group.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 2 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-API-OPT-IN/google_secret_manager_secret.django_admin_password` (alias `convert:api:secrets-manager-vault:v1:unknown:API_OPT_IN`): Allow calls of the Secrets Manager Vault-compatible API, whose maturity is not established, for this migration (the API may change or vanish)? Accept: the calls of the Secrets Manager Vault-compatible API (WriteSecret) are carried out for google_secret_manager_secret.django_admin_password, google_secret_manager_secret.django_settings. Refuse: no call is made, a refusal selects no other path (the draft holds no other carrier of what the calls set), and what they set stays open for google_secret_manager_secret.django_admin_password, google_secret_manager_secret.django_settings. · the Secrets Manager Vault-compatible API is of a maturity that is not established (its documentation states no release status and its product documentation does not establish it as generally available): the execution plan executes no call of an API that is not generally available without an explicit opt-in, so the calls of it and the steps of its path for google_secret_manager_secret.django_admin_password, google_secret_manager_secret.django_settings wait for this decision; the draft's own blocks do not
  - decision `DEC-GEN-CONVERT-PROPOSED-ALTERNATIVE/google_secret_manager_secret_iam_binding.django_settings` (alias `convert:google_secret_manager_secret_iam_binding.django_settings:proposal:PROPOSED_ALTERNATIVE`): Decide whether the proposed STACKIT alternative replaces google_secret_manager_secret_iam_binding.django_settings: read the module proposals/proposal_django_settings, accept the difference and set its values, or design it another way · the target has no equal of this the members of one role on the Secret Manager secret: A STACKIT role assignment is not a grant on the Secret Manager secret. It gives one user, group or service account one STACKIT role on a whole project, folder or organisation. The role is a set of STACKIT permissions, not the Google role, and no table maps one to the other. It has no condition and no public member, so what the grant gave to a Google group, a domain, a federated identity or everyone is named again, and the access reaches more than the Secret Manager secret. A binding on a secret group applies to every secret in the group, so it is wider than a grant on one secret unless the secret has a group of its own, and its roles are Secrets Manager roles. The binding was authoritative for its role: STACKIT role assignments are additive, so a person who holds the role through another assignment keeps it, and removing such people is a step of a person. To decide: Which STACKIT role, on which project, folder or organisation, gives the same people the access they need on the Secret Manager secret, knowing it covers everything in that scope; which STACKIT users, groups or service accounts take the place of Google groups, domains, federated identities and a public member; and whether the grant ends with the Secret Manager secret when it has no replacement. For secrets: which secret group holds the secret, who else shares that group, and which Secrets Manager role and subject take the grant. Whether people who hold the role through another assignment keep it. The draft of google_secret_manager_secret.django_settings stands as it is: this answer decides the module and nothing of that draft.
- **Includes:** `google_secret_manager_secret_iam_binding.django_settings`, `google_secret_manager_secret_version.django_settings`
- **Depends on:** `google_service_account.automation`, `google_service_account.server`, `google_sql_database_instance.postgres`, `google_storage_bucket.media`
- **WARNING** (secret-iam-access): The secret has grants for individual principals. Access on STACKIT Secrets Manager is coarser than a Secret Manager grant: a Secrets Manager user is read-only or read-write for the whole secrets engine of its instance, with no scope to one secret or path. Narrower access exists only as role bindings on the instance or on a secret group (a named list of secrets) in the alpha API of the service, and the pinned provider offers them as resources of its experimental IAM feature (stackit_secretsmanager_instance_role_binding_v1 and stackit_secretsmanager_secret_group_role_binding_v1), which its documentation says may change or be removed; the specification does not list the roles a secret group accepts. A grant of one Google principal on one secret therefore cannot be carried one to one: decide per principal whether it gets a user of the whole instance, a role binding on a secret group of the secrets it may read, or a separate Secrets Manager instance.
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Inherited placement:** provider configuration `google`, source region `us-central1`.
- **Critical semantics left to you to decide or accept (3):** secret-value, secret-settings, tcr-secret-id
- **Property accounting:** 5 of 5 meaningful properties accounted
- **5 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (2; REVIEW 2): `google_secret_manager_secret_iam_binding.django_settings.members`, `google_secret_manager_secret_iam_binding.django_settings.role` — NOT CARRIED (google_secret_manager_secret_iam_binding.django_settings): members, role = roles/secretmanager.secretAccessor — the API step API/secrets-manager-vault/WriteSecret/google_secret_manager_secret.django_settings writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
  - secret handling (2; REVIEW 2): `secret_id`, `google_secret_manager_secret_version.django_settings.secret_data` — NOT CARRIED (google_secret_manager_secret.django_settings): replication, secret_id — the API step API/secrets-manager-vault/WriteSecret/google_secret_manager_secret.django_settings writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
  - residency compliance (1; REVIEW 1): `replication.user_managed.replicas.location` — NOT CARRIED (google_secret_manager_secret.django_settings): replication, secret_id — the API step API/secrets-manager-vault/WriteSecret/google_secret_manager_secret.django_settings writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
- **Why those are open, and what closes them:**
  - `secret-value`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_secret_manager_secret_version.secret_data: the value of the secret. StackToIT never reads it and never writes it into the draft; the API step of the secret writes the document the customer supplies. Closes when: A person decides where the value comes from, supplies the document and the step has run.
  - `secret-settings`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The settings of the secret beside its value (secret-value): STACKIT replicates it itself (no replica locations or per-replica keys), tags and version states have no counterpart, and IAM members and policy map to Secrets Manager users (read-only or read-write for a whole instance) or to experimental role bindings on a secret group — REVIEW. Closes when: A person recreates the secret in the Secrets Manager instance, since its data is not written into the draft, and decides for each IAM member whether it gets a user of the whole instance, a role binding on a secret group, or a separate instance.
  - `tcr-secret-id`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_secret_manager_secret.secret_id: The secret's own resource identifier; access to the secret's value is controlled by IAM bindings and replication/encryption settings, not by the id string itself. Closes when: A person confirms the secret name in STACKIT Secrets Manager against what refers to the source secret ID, or accepts the new name.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs security/secrets-manager 2026-09-23; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/security/secrets-manager/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/secretsmanager_instance

#### `google_service_account.init`

- **Source:** `google_service_account` — iam.tf:61
- **Standing:** conditional — whether it exists is decided only when a plan runs; the class below is the one it would get, it is not counted in the totals and not automation-eligible.
- **Candidate target:** STACKIT service account (`stackit_service_account`, `stackit_authorization_project_role_assignment`, `stackit_authorization_folder_role_assignment`, `stackit_authorization_organization_role_assignment`, `stackit_authorization_service_account_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_folder_role_assignment` (capability `identity.role-assignment`), `stackit_authorization_organization_role_assignment` (capability `identity.role-assignment`), `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`), `stackit_authorization_service_account_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_folder_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_authorization_organization_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_authorization_service_account_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `gcp.service_account/service-account`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic role-bindings, semantic account-name); a point the scan could not establish
- **Why:** A Google service account becomes a STACKIT service account named after its account ID (shortened to the STACKIT name rules, so its e-mail address changes and every reference to it is updated). What the account may do is what the IAM resources of the estate grant it, and the draft carries that where it can show the mapping: a grant to the account on a project, a folder or an organisation becomes a STACKIT role assignment of the account. The role is written as it is only where the Google role has a STACKIT role with the same permissions or fewer on a project; every other role is an input without a default that names the candidates and how they differ, because a wider role is never a default. A grant that lets another account act as this one becomes an Act-As assignment. Grants that cannot be written are listed in the draft with the reason: a condition (a STACKIT role assignment has none), a policy document, a repeated grant, a role or a member that is not visible statically, and a member that is a person, a group or the identity of a Kubernetes workload. An additive grant (a member) adds one member and removes none, as a role assignment does; a binding or a policy removes every member of its role that it does not list, a role assignment never removes anyone, and the draft marks each such grant. The workloads that ran as the account are not attached to it by this block; workloads that got credentials from the metadata server or GKE Workload Identity need explicit STACKIT credentials or a federated identity. Keys are never carried.
- **INFO** (sa-account-id-not-visible): The account ID is not visible statically; the STACKIT account is named after the source address. — a variable's default, not a fact
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Inherited placement:** provider configuration `google`, source region `us-central1`.
- **Critical semantics left to you to decide or accept (2):** role-bindings, account-name (**not automation-eligible**: no property the unit sets is read by role-bindings)
- **Property accounting:** 2 of 2 meaningful properties accounted
- **1 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (1; REVIEW 1): `account_id` — NOT CARRIED (google_service_account.init): account_id — the account ID is not visible statically, or the account is declared several times: the STACKIT account is named after the source address.
- **Why those are open, and what closes them:**
  - `role-bindings`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The grants of the estate that name the account: a grant on a project, a folder or an organisation is written as a STACKIT role assignment of the account when its role and members are visible statically and it has no condition, and a grant that lets another account act as it is written as an Act-As assignment. A Google role is written as a STACKIT role only where the mapping shows the STACKIT role holds the same permissions or fewer on a project; every other role is an input that names the candidates, and a person confirms each. A binding or a policy is authoritative (it removes the members of its role that it does not list) and a role assignment only adds, which the draft says on each: members that hold the role outside the configuration keep it on STACKIT until a person removes them. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `account-name`: A check of the knowledge base (sa account id not visible) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The account ID becomes the stackit_service_account name (shortened to the STACKIT name rules; pinned provider) — TRANSFORMED; the e-mail address changes. An ID not visible statically (or a repeated account) is named NOT CARRIED — REVIEW (check sa-account-id-not-visible). Closes when: A person decides what this finding asks, and records the evidence or the decision. The finding says: The account ID is not visible statically; the STACKIT account is named after the source address. — a variable's default, not a fact.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

### Messaging

#### `google_pubsub_topic.faux`

- **Source:** `google_pubsub_topic` — postdeployment.tf:32
- **Candidate target:** STACKIT RabbitMQ (`stackit_rabbitmq_instance`, `stackit_rabbitmq_credential`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Classification:** REPLATFORM · **Confidence:** MEDIUM · rule `gcp.pubsub_topic/pubsub`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (semantic tc-name); a point the scan could not establish
- **Why:** A topic maps to a RabbitMQ exchange and each subscription to a bound queue. Publishers and subscribers switch from the Pub/Sub client to AMQP; acknowledgement deadlines, retries and dead-letter topics map to acknowledgements, requeueing and dead-letter exchanges. STACKIT also publishes a PubSub API (beta) with topics and pull subscriptions, for which the STACKIT provider has no resource: the draft states it as the candidate beside the RabbitMQ instance, behind the opt-in of the beta API, as calls of the execution plan, and what the API has no field for (push delivery, filters, dead-letter topics, ordering, a customer-managed key) is a step of its own. The RabbitMQ instance is the path carried out until that opt-in is accepted; accepting it makes PubSub the target of the topic instead, never both.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-API-OPT-IN/google_pubsub_topic.faux` (alias `convert:api:pubsub:v1beta:beta:API_OPT_IN`): Allow calls of the beta pubsub API v1beta for this migration (the API may change or vanish)? Accept: the pubsub API v1beta path is carried out for google_pubsub_topic.faux: its calls become executable. the RabbitMQ instance the draft writes stays in the draft this run wrote, so its step is held (REGENERATE_REQUIRED) until a draft is generated without it (answer target.messaging.path with pubsub in the inputs file and run again); an instance shared with a queue or topic that has no call of the pubsub API v1beta path stays taken. Refuse: the RabbitMQ instance the draft writes is carried out and the calls and steps of the pubsub API v1beta path are not taken. · the pubsub API v1beta is beta: the execution plan executes no call of an API that is not generally available without an explicit opt-in, so the calls of it and the steps of its path for google_pubsub_topic.faux wait for this decision; the draft's own blocks do not
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Inherited placement:** provider configuration `google`, source region `us-central1`.
- **Critical semantics left to you to decide or accept (1):** tc-name
- **Property accounting:** 1 of 1 meaningful properties accounted
- **1 critical setting(s) left to you** — **not automation-eligible**:
  - workload compatibility (1; REVIEW 1): `name` — NOT CARRIED (google_pubsub_topic.faux): name — the topic becomes an exchange and its subscriptions queues of the shared RabbitMQ instance, created in RabbitMQ by hand (not by this draft): names, delivery, retention and push settings are not generated.
- **Why those are open, and what closes them:**
  - `tc-name`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_pubsub_topic.name: The topic's own resource name, which publishers and subscribers address it by; access to it is controlled by IAM, not by the name string itself, and a changed name breaks every client that uses the old one. Closes when: A person confirms the topic name the replacement messaging service carries against the publishers and subscribers that use it, or accepts the new name.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs messaging/rabbitmq 2026-09-23; STACKIT catalogue eu01 2026-09-24 (RabbitMQ 4.1); checked 2026-11-05: the pinned provider schema 0.121.0 holds no pubsub resource (0 hits), stackit-api-specifications services/pubsub holds v1alpha and v1beta (the repository embeds v1beta in STACKIT API specification pubsub_v1beta: topics, pull subscriptions, publishers and subscribers; no push, filter, dead-letter, ordering or encryption field); found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/messaging/rabbitmq/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/rabbitmq_instance · https://github.com/stackitcloud/stackit-api-specifications/tree/main/services/pubsub/v1beta

### Network

#### `google_firebase_hosting_site.client`

- **Source:** `google_firebase_hosting_site` — firebase.tf:24
- **Standing:** conditional — whether it exists is decided only when a plan runs; the class below is the one it would get, it is not counted in the totals and not automation-eligible.
- **Candidate target:** STACKIT Object Storage as origin of a STACKIT CDN distribution, with a custom domain (`stackit_objectstorage_bucket`, `stackit_cdn_distribution`, `stackit_cdn_custom_domain`)
- **Target maturity:** BETA · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is beta (the provider: "may be subject to breaking changes in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_cdn_custom_domain` (capability `cdn.custom-domain`), `stackit_cdn_distribution` (capability `cdn.distribution`).
- **GA target:** no GA target yet: stackit_cdn_custom_domain is beta in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **GA target:** no GA target yet: stackit_cdn_distribution is beta in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** REDESIGN · **Confidence:** LOW · rule `gcp.firebase_hosting_site/web-hosting-site`
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (semantic migration-decision, semantic tc-firebase-hosting-site-project, semantic tcr-firebase-hosting-site-site-id, semantic linked-dependency:google_firebase_project); a point the scan could not establish
- **Why:** A Firebase Hosting site: the unit of hosting, whose identifier builds the Firebase-provided sub-domains, optionally associated with a Firebase web app. Firebase Hosting is Google's web hosting with a global CDN: a site holds versions (the files with the rewrites, redirects and headers of firebase.json), releases publish a version on a channel, preview channels expire by themselves, and custom domains get a certificate. STACKIT has no web hosting service of this kind (0 hits for firebase in the resource names, descriptions and attributes of the 115 resource types of the pinned STACKIT provider, checked 2026-11-05; the product list at docs.stackit.cloud/products/ read 2026-11-05 names none), but it has the parts for static content: Object Storage buckets, and a CDN whose distribution can use a bucket as its origin and takes redirect rules, TLS settings and a WAF (the stackit_cdn_distribution resource of the pinned provider is a beta resource), with custom domains. Rewrites to Cloud Run services or Cloud Functions, preview channels and the release history of a site have no counterpart there. Static files are published into an Object Storage bucket by a pipeline; a CDN distribution with the bucket as origin serves them on a custom domain, and the redirects of firebase.json become redirect rules of the distribution. Preview channels and release history are rebuilt in the pipeline (one bucket path per preview). Rewrites to dynamic backends need a load balancer or another origin, which a person decides.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-PROPOSED-ALTERNATIVE/google_firebase_hosting_site.client` (alias `convert:google_firebase_hosting_site.client:proposal:PROPOSED_ALTERNATIVE`): Decide whether the proposed STACKIT alternative replaces google_firebase_hosting_site.client: read the module proposals/proposal_client, accept the difference and set its values, or design it another way · the target has no equal of this static web hosting site: Static files are published into an Object Storage bucket by a pipeline, and a CDN distribution (a beta resource) with the bucket as origin serves them on a custom domain; the redirects of the site become redirect rules of the distribution. Custom response headers, rewrites to Cloud Run services or Cloud Functions, preview channels and the release history have no counterpart and are restated in the pipeline or in the application. To decide: Which bucket is the origin, which domain the distribution serves, and how rewrites and previews are replaced. The CDN resources are beta.
- **Depends on:** `google_firebase_project.default`
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (linked-dependency-unread): This unit names google_firebase_project.default (google_firebase_project), whose own decision the target does not carry (it is MANUAL_REVIEW), and the semantic contract of google_firebase_hosting_site does not read google_firebase_project, so what the reference becomes is not assessed.
- **Inherited placement:** provider configuration `google-beta`, source region `us-central1`.
- **Critical semantics left to you to decide or accept (2):** tc-firebase-hosting-site-project, tcr-firebase-hosting-site-site-id (**not automation-eligible**: no property the unit sets is read by linked-dependency:google_firebase_project)
- **2 critical setting(s) left to you** (not drafted — REDESIGN) — **not automation-eligible**:
  - identity access (1; REVIEW 1): `project`
  - workload compatibility (1; REVIEW 1): `site_id`
- **Why those are open, and what closes them:**
  - `tc-firebase-hosting-site-project`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_firebase_hosting_site.project (identity access): The Google Cloud project the resource is created in. IAM policy, organisation policy and audit configuration are inherited from the project, so it decides who can act on the resource and what it is isolated from. The unit names google_firebase_project.default (google_firebase_project) through this setting (the target does not carry it: it is MANUAL_REVIEW), so what the reference becomes is part of this setting. Closes when: A person decides which STACKIT project, and with it which access rules, holds the replacement.
  - `tcr-firebase-hosting-site-site-id`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_firebase_hosting_site.site_id (workload compatibility): A globally unique identifier for the Hosting site; other settings, bindings and clients refer to the object by this id. Firebase Hosting has no STACKIT counterpart, so the site is rebuilt on Object Storage with a CDN. Closes when: A person sets this up on the bucket, the CDN distribution and the domain that replace Firebase Hosting, or decides to drop it, and records the decision.
- **Review:**
  - [ ] Check the rewrites, headers and clean-URL settings of firebase.json: redirects have a counterpart in the CDN, rewrites to a backend do not.
  - [ ] Plan the DNS change for the custom domain and the certificate that the CDN issues for it.
- **Evidence** (validated against terraform-provider-stackit@0.121.0 (provider schema: none of its 115 resource types is a web hosting service; 0 hits for firebase in resource names, descriptions and attributes, checked 2026-11-05); docs.stackit.cloud product list read 2026-11-05 (nearest: Object Storage (S3-compatible) as the origin of a CDN distribution with redirect rules and custom domains); hashicorp/google 8.4.0 schema and docs of the type): https://registry.terraform.io/providers/hashicorp/google/8.4.0/docs/resources/firebase_hosting_site · https://docs.stackit.cloud/products/ · https://docs.stackit.cloud/products/storage/object-storage/ · https://docs.stackit.cloud/products/network/load-balancing-and-content-delivery/cdn/basics/features-cdn/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.121.0/docs/resources/objectstorage_bucket · https://registry.terraform.io/providers/stackitcloud/stackit/0.121.0/docs/resources/cdn_distribution · https://registry.terraform.io/providers/stackitcloud/stackit/0.121.0/docs/resources/cdn_custom_domain

### Platform

#### `google_firebase_project.default`

- **Source:** `google_firebase_project` — firebase.tf:17
- **Classification:** MANUAL_REVIEW · **Confidence:** LOW · rule `gcp.firebase_project/app-platform-project`
- **Feasibility:** UNKNOWN — blocked by a point the scan could not establish
- **Why:** The enabling of Firebase on a Google Cloud project. Once Firebase has been added to a project it cannot be removed from it. Firebase is Google's backend platform for mobile and web apps. A Firebase project and the registration of an Android or Apple app in it hold the identity of the app (package name or bundle id, signing hashes, team id) and the API key through which the app reaches Firebase services. STACKIT has no mobile or web application backend platform: none of the 115 resource types of the pinned STACKIT provider is one (0 hits for firebase in resource names, descriptions and attributes, checked 2026-11-05), and the product list at docs.stackit.cloud/products/ (read 2026-11-05) names none. The registration itself therefore has nothing to move to; a person decides, app by app, which backend replaces the Firebase services the app uses.
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Inherited placement:** provider configuration `google-beta`, source region `us-central1`.
- **Critical semantics left to you to decide or accept (1):** tc-firebase-project-project
- **1 critical setting(s) left to you** (not drafted — MANUAL_REVIEW) — **not automation-eligible**:
  - identity access (1; REVIEW 1): `project`
- **Why those are open, and what closes them:**
  - `tc-firebase-project-project`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. google_firebase_project.project (identity access): The Google Cloud project the resource is created in. IAM policy, organisation policy and audit configuration are inherited from the project, so it decides who can act on the resource and what it is isolated from. Firebase has no STACKIT counterpart, so the registration of the app is not moved and the backend the app talks to is chosen by a person. Closes when: A person decides which STACKIT project, and with it which access rules, holds the replacement.
- **Review:**
  - [ ] List the Firebase services each app uses (authentication, database, storage, messaging, remote config); each needs its own replacement.
  - [ ] The signing keys and store listings stay with Google Play and the Apple App Store; only the backend the app talks to moves.
- **Evidence** (validated against terraform-provider-stackit@0.121.0 (provider schema: none of its 115 resource types is a mobile or web application backend platform; 0 hits for firebase in resource names, descriptions and attributes, checked 2026-11-05); docs.stackit.cloud product list read 2026-11-05 (nearest: Kubernetes Engine and the managed databases (the parts a replacement backend is built from)); hashicorp/google 8.4.0 schema and docs of the type): https://registry.terraform.io/providers/hashicorp/google/8.4.0/docs/resources/firebase_project · https://docs.stackit.cloud/products/ · https://docs.stackit.cloud/products/runtime/kubernetes-engine/

### Storage

#### `google_storage_bucket.media`

- **Source:** `google_storage_bucket` — storage.tf:17
- **Candidate target:** STACKIT Object Storage (`stackit_objectstorage_bucket`, `stackit_objectstorage_credentials_group`, `stackit_objectstorage_credential`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `gcp.storage_bucket/gcs`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (check gcs-force-destroy, semantic geo-replication, semantic bucket-region, semantic iam-access and 4 more); a point the scan could not establish
- **Why:** A bucket maps to a STACKIT Object Storage bucket. Clients already using the S3-compatible XML API with HMAC keys only change endpoint and keys; clients using the Google Cloud Storage libraries (JSON API) switch to an S3 SDK. Data is copied with rclone.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 2 open decisions (3 questions), 0 manual actions
  - decision `DEC-GEN-CONVERT-SOURCE-REGION-MAPPING` (alias `convert:estate:source_location:SOURCE_REGION_MAPPING`): Map each source location of the estate to a STACKIT region · The source places its units in a location the scan cannot read (the value comes from an input a plan can change, or the source does not state it). No mapping between Google and STACKIT regions is evidenced, so the region the draft builds in is not shown to hold the residency of a source location: a person states it once for the estate, by answering target.region.source_location for each location.
  - decision `DEC-GEN-CONVERT-PROPOSED-ALTERNATIVE/google_storage_bucket_iam_member.automation` (alias `convert:google_storage_bucket_iam_member.automation:proposal:PROPOSED_ALTERNATIVE`): Decide whether the proposed STACKIT alternative replaces google_storage_bucket_iam_member.automation: read the module proposals/proposal_automation, accept the difference and set its values, or design it another way · the target has no equal of this one member's role on the Cloud Storage bucket: A STACKIT credentials group is not a grant on the Cloud Storage bucket. It is the principal that a bucket policy names, a set of S3 keys with no Google identity behind it, and by itself it gives no access to the bucket and takes none away. The statement that grants it something is a statement of the bucket policy, in the policy language of STACKIT (a credentials group or * as the principal, S3 actions, five condition keys), which no Terraform resource sets. The Google role is not mapped to S3 actions by any table, the condition of the grant has no counterpart unless it can be written with those five condition keys, and a Google group, a domain, a federated identity and allUsers or allAuthenticatedUsers are named again as credentials groups or as *. To decide: Which credentials group stands for each member of the grant, which S3 actions of the bucket policy give the same people the access they need and no more than the Google role gave, what becomes of the condition, of public members (allUsers, allAuthenticatedUsers), of Google groups, domains and federated identities, and whether the grant ends with the Cloud Storage bucket when it has no replacement. Which bucket the grant is on, because the scan does not hold it. The draft of google_storage_bucket.media stands as it is: this answer decides the module and nothing of that draft.
  - decision `DEC-GEN-CONVERT-PROPOSED-ALTERNATIVE/google_storage_bucket_iam_member.server` (alias `convert:google_storage_bucket_iam_member.server:proposal:PROPOSED_ALTERNATIVE`): Decide whether the proposed STACKIT alternative replaces google_storage_bucket_iam_member.server: read the module proposals/proposal_server, accept the difference and set its values, or design it another way · the target has no equal of this one member's role on the Cloud Storage bucket: A STACKIT credentials group is not a grant on the Cloud Storage bucket. It is the principal that a bucket policy names, a set of S3 keys with no Google identity behind it, and by itself it gives no access to the bucket and takes none away. The statement that grants it something is a statement of the bucket policy, in the policy language of STACKIT (a credentials group or * as the principal, S3 actions, five condition keys), which no Terraform resource sets. The Google role is not mapped to S3 actions by any table, the condition of the grant has no counterpart unless it can be written with those five condition keys, and a Google group, a domain, a federated identity and allUsers or allAuthenticatedUsers are named again as credentials groups or as *. To decide: Which credentials group stands for each member of the grant, which S3 actions of the bucket policy give the same people the access they need and no more than the Google role gave, what becomes of the condition, of public members (allUsers, allAuthenticatedUsers), of Google groups, domains and federated identities, and whether the grant ends with the Cloud Storage bucket when it has no replacement. Which bucket the grant is on, because the scan does not hold it. The draft of google_storage_bucket.media stands as it is: this answer decides the module and nothing of that draft.
- **Includes:** `google_storage_bucket_iam_member.automation`, `google_storage_bucket_iam_member.server`
- **Depends on:** `google_service_account.automation`, `google_service_account.server`
- **INFO** (gcs-iam): Bucket access is granted with IAM bindings or ACL entries; on STACKIT it becomes bucket policies and Object Storage credentials.
- **INFO** (gcs-public): Not verifiable statically (member of facet `google_storage_bucket_iam_member.automation`, member of facet `google_storage_bucket_iam_member.server` not visible): The bucket is readable by anyone (allUsers or allAuthenticatedUsers). STACKIT Object Storage expresses this as a bucket policy (documented sample: "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject" on the bucket's objects); "*" is anonymous access, which also covers allAuthenticatedUsers. Re-create it only if still intended, or serve the content through the CDN.
- **WARNING** (gcs-force-destroy): force_destroy lets Terraform delete the bucket together with its objects. STACKIT has no such override: stackit_objectstorage_bucket (the pinned STACKIT provider) "cannot be destroyed if the bucket contains objects" — empty the bucket (or migrate its objects) before destroying it.
- **WARNING** (source-provider-unverified): no lock file records the version of registry.terraform.io/hashicorp/google, and the constraint ">= 6, < 8" excludes it (pinned 8.4.0) (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (7):** geo-replication, bucket-region, iam-access, iam-grant, public-access, force-destroy, tc-storage-bucket-name
- **Property accounting:** 8 of 8 meaningful properties accounted
- **7 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (4; REVIEW 4): `google_storage_bucket_iam_member.automation.member`, `google_storage_bucket_iam_member.automation.role`, `google_storage_bucket_iam_member.server.member`, `google_storage_bucket_iam_member.server.role` — NOT CARRIED (google_storage_bucket_iam_member.automation): member, role = roles/storage.admin — the draft of google_storage_bucket.media does not carry this one member's role on the Cloud Storage bucket.
  - deletion protection (1; UNSUPPORTED 1): `force_destroy` — NOT CARRIED (google_storage_bucket.media): force_destroy = true — stackit_objectstorage_bucket has no force-destroy override (pinned provider): deleting a bucket that still holds objects behaves as STACKIT's Object Storage API defines it — empty the bucket (or migrate its objects) before it is destroyed.
  - residency compliance (1; REVIEW 1): `location`
  - workload compatibility (1; REVIEW 1): `name`
- **Why those are open, and what closes them:**
  - `geo-replication`: The value is read from a variable's default; that is not a fact of the source. A custom_placement_config not visible statically (a dynamic block over an unknown for_each, a whole value from a variable) may be absent: the facts state no replication, the ledger writes no line and a person decides (REVIEW by the case; 2026-09-25 unknown-value audit — it used to be claimed as replicated). Closes when: The value is set where the module is called (a literal), the variable is given its value in a variable file of the scan (--var-file), or a person confirms the value production uses.
  - `bucket-region`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. A single-region location (us-central1, europe-west3, ...), or one not visible statically: the draft sets no region on stackit_objectstorage_bucket (`region`: "if not defined, the provider region is used", pinned provider), so the bucket lands in the STACKIT region the user sets, not in the source's — a person confirms the residency — REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `iam-access`: A check of the knowledge base (gcs iam) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The setting states who may access the bucket, granted with IAM bindings or ACL entries. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded. A person creates the bucket policies and Object Storage credentials that give the same access on STACKIT.
  - `iam-grant`: A check of the knowledge base (gcs iam) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The value-level reader of who gets which role (`iam-access` above is the facet as a whole): role, member(s) and condition. A GCP principal (user:, group:, serviceAccount:, allUsers) and a predefined role have no STACKIT counterpart in a bucket policy, whose statements name principals and S3 actions (supported-permissions-in-bucket-policies docs; the draft writes no policy) — a person translates each grant — REVIEW for every value, allUsers included (that one is also public-access, TRANSFORMED). Closes when: A person decides what this finding asks, and records the evidence or the decision. The finding says: Bucket access is granted with IAM bindings or ACL entries; on STACKIT it becomes bucket policies and Object Storage credentials.
  - `public-access`: A check of the knowledge base (gcs public) needs a value the scan cannot read statically, so it could not decide. The counterpart is a bucket policy with Principal "*" and s3:GetObject (documented sample), but stackit_objectstorage_bucket has no policy attribute and the provider no bucket-policy resource, so the draft writes none: REVIEW, as for the IP rules. Closes when: A literal value or a resolved reference in the source lets the check decide, or a person verifies the value.
  - `force-destroy`: A check of the knowledge base (gcs force destroy) found a setting the target has no counterpart for (a finding of this unit describes it). stackit_objectstorage_bucket (pinned provider) "cannot be destroyed if the bucket contains objects" (schema description): force_destroy = false — a destroy that stops at a non-empty bucket — is what STACKIT does, PRESERVED; true has no counterpart, UNSUPPORTED (check gcs-force-destroy). Closes when: A person accepts the difference or the design changes: nothing in the source can make the target carry it.
  - and 1 kind of reason more (engineering/analysis-details.md)
- **Review:**
  - [ ] Find which applications use the Google client libraries or signed URLs — those need a code change.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs object-storage 2026-09-23 (S3-compatible, object lock since 2026-04); GCS XML API interoperability; docs object-storage supported operations and bucket policies 2026-09-27; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/storage/object-storage/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/objectstorage_bucket · https://docs.cloud.google.com/storage/docs/interoperability

## Support resources — critical settings left to a person

The draft creates nothing for these resources; the units that use them are drafted without them. Every critical setting they state is listed so that it is decided on the target, not lost.

| Support resource | Type | Critical settings |
|---|---|---|
| `google_cloud_run_service_iam_policy.server_noauth` | google_cloud_run_service_iam_policy | `google_cloud_run_service_iam_policy.server_noauth.location` (CRITICAL/CLOSED:REVIEW), `google_cloud_run_service_iam_policy.server_noauth.policy_data` (CRITICAL/CLOSED:REVIEW), `google_cloud_run_service_iam_policy.server_noauth.project` (CRITICAL/CLOSED:REVIEW), `google_cloud_run_service_iam_policy.server_noauth.service` (CRITICAL/CLOSED:REVIEW) |
| `google_project_iam_member.automation_permissions` | google_project_iam_member | `google_project_iam_member.automation_permissions.member` (CRITICAL/CLOSED:REVIEW), `google_project_iam_member.automation_permissions.project` (CRITICAL/CLOSED:REVIEW), `google_project_iam_member.automation_permissions.role` (CRITICAL/CLOSED:REVIEW) |
| `google_project_iam_member.client_permissions` | google_project_iam_member | `google_project_iam_member.client_permissions.member` (CRITICAL/CLOSED:REVIEW), `google_project_iam_member.client_permissions.project` (CRITICAL/CLOSED:REVIEW), `google_project_iam_member.client_permissions.role` (CRITICAL/CLOSED:REVIEW) |
| `google_project_iam_member.init_permissions` | google_project_iam_member | `google_project_iam_member.init_permissions.member` (CRITICAL/CLOSED:REVIEW), `google_project_iam_member.init_permissions.project` (CRITICAL/CLOSED:REVIEW), `google_project_iam_member.init_permissions.role` (CRITICAL/CLOSED:REVIEW) |
| `google_project_iam_member.server_permissions` | google_project_iam_member | `google_project_iam_member.server_permissions.member` (CRITICAL/CLOSED:REVIEW), `google_project_iam_member.server_permissions.project` (CRITICAL/CLOSED:REVIEW), `google_project_iam_member.server_permissions.role` (CRITICAL/CLOSED:REVIEW) |
| `module.project_services.google_project_service.project_services` | google_project_service | `module.project_services.google_project_service.project_services.disable_dependent_services` (CRITICAL/CLOSED:REVIEW), `module.project_services.google_project_service.project_services.disable_on_destroy` (CRITICAL/CLOSED:REVIEW), `module.project_services.google_project_service.project_services.project` (CRITICAL/CLOSED:REVIEW), `module.project_services.google_project_service.project_services.service` (CRITICAL/CLOSED:REVIEW) |

## Scan diagnostics

What the scanner could not see or decide — read before trusting the numbers.

- **info** unconsumed-lookup: data.google_client_config.current (data source google_client_config) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (postdeployment.tf:28)
- **info** unconsumed-lookup: data.http.execute_activategcb_trigger (data source http) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (postdeployment.tf:72)
- **info** unconsumed-lookup: data.http.execute_init_trigger (data source http) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (postdeployment.tf:250)
- **info** unconsumed-lookup: data.http.execute_placeholder_trigger (data source http) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (postdeployment.tf:126)

---

*StackToIT does not deploy, modify the source environment or STACKIT, migrate data or perform cutover. Classifications come from the knowledge-base rules cited under each unit.*
