What this change is
Task 15 stages a credential reference. It writes a pointer to a 1Password vault item into the cluster and stops there. Everything that would prove the credential is usable — and everything that would actually deliver an alert — belongs to later, separately gated tasks.
- Adds exactly one Terraform resource: a
OnePasswordItemcustom resource in namespacekube-prometheus-stack. - Points it at a single vault item path. The manifest carries a path and nothing else.
- Adds a validator that pins that manifest to an exact literal shape and rejects three concrete mutations.
- Adds a narrowly scoped exemption so the existing no-delivery guard tolerates the new resource's own name.
- It does not show the credentials are valid. Nothing authenticates against Matrix anywhere in this change.
- It does not show Matrix delivery is active. No Matrix receiver, route, or webhook exists, and every alert still routes to the built-in
nullsink. - It does not verify the vault item actually holds the five expected fields.
- It was not applied. No merge, no
terraform apply, no Secret read, no workflow dispatch.
The staged object
The entire resource added to tf/modules/prometheus-stack/main.tf. The validator asserts the manifest is byte-for-byte this and has exactly the four keys apiVersion, kind, metadata, spec — with spec containing only itemPath.
resource "kubernetes_manifest" "matrix_alertmanager_receiver" { manifest = { apiVersion = "onepassword.com/v1" kind = "OnePasswordItem" metadata = { name = "matrix-alertmanager-receiver" namespace = "kube-prometheus-stack" } spec = { itemPath = "vaults/kubernetes-vault/items/alertmanager_matrix_receiver" } } }
module.prometheus_stack
.kubernetes_manifest
.matrix_alertmanager_receiver
vaults/kubernetes-vault
/items/alertmanager_matrix_receiver
No fields block, no value, no depends_on, no lifecycle. The validator requires the resource body to hold the single key manifest.
The five-key map
Five 1Password field labels are intended to materialize as five identically named keys on the resulting Secret.
Change map — staging, materialization, and the gate
Solid lanes are created or enforced by this PR. Dashed lanes are runtime behaviour or future work that this PR deliberately does not perform. Hover a lane to isolate it.
Declares the pointer and nothing else. The manifest carries a path, not a value, so there is no credential for Terraform to render or persist; the reviewed plan artifact is redacted to structure only.
Behaviour of the already-installed operator once the custom resource exists. This is where values first appear, entirely outside Terraform's view.
Everything above is a reference: a path, a name, a namespace. Nothing above proves the referenced item exists, holds the five expected fields, or contains working credentials. No semantic claim crosses this line.
The sole place where the credentials are actually judged. It binds its verdict to the specific Secret it inspected, by UID and resourceVersion, so a later rotation cannot silently inherit a stale pass.
Zero Matrix delivery resources exist today. Alertmanager still declares a single built-in null receiver and routes every alert to it, which is the standing no-delivery safeguard. The Task 9 contract fails the build if core tries to add real delivery, and that guard is unchanged outside one path-scoped exemption.
Plan outcome
The reviewed artifact is a redacted plan manifest — structure without values. Its schema is asserted, not assumed.
# module.prometheus_stack # .kubernetes_manifest # .matrix_alertmanager_receiver actions = ["create"] delete_count = 0 replace_paths = []
- Exactly one non-
no-opresource change is permitted; more than one fails the contract. - The validator accepts only
["create"]or["update"]. The observed plan is create. - Any
deleteaction or any replacement path fails closed — one of the three negative test cases proves it.
The manifest may contain exactly three top-level keys, and each resource change exactly nine. The absent keys are the point:
# allowed per change address, module_address, mode, type, name, actions, replace_paths, before_sensitive, after_sensitive # absent by assertion — this is the redaction before, after
Because before and after are rejected outright, the reviewed artifact structurally cannot carry a value, rather than merely happening not to.
- Workflow run
- 32109226912 · attempt 1 · success
- Artifact
- 9314286884
terraform-speculative-plan-052418a0… - tfplan sha256
- 772a78a5cbdec7dedc81aed2fb648982185d3e34ee54abb119f1765515a374db
- plan manifest sha256
- 5221b470126d4fafab540ff7973534e2db5ec4b2576f7983efbd860dfe4f61d5
- Remote run
- run-tx4LXcN2EtjtqG4N
- Artifact expires
- 2026-08-19T06:59:59Z
File by file
Three files, all inside tf/modules/prometheus-stack. Nothing else in the repository is touched.
The staged resource itself, added above the existing Grafana password resource. It is the only Matrix-related resource in a 444-line module whose other twenty resources are Grafana, Prometheus, Pushgateway, ingresses and dashboard ConfigMaps.
Why here: the Secret must land in the same namespace as the Alertmanager that will eventually consume it, so the reference belongs to the Prometheus Stack module rather than a separate one.
A standalone contract validator. It parses main.tf with python-hcl2, requires the staging resource to be the sole one of its name, and compares the manifest against an expected literal — so any drift in path, name, namespace, or shape fails.
It then runs three negative cases, each a deep copy mutated and required to be rejected: a wrong itemPath, an added depends_on, and a plan whose action is delete. Testing that the guard refuses bad input is what gives the positive assertion its weight.
Note on invocation: the plan-manifest half only runs when a plan path is passed as an argument. Invoked bare, it validates source and mutation cases only.
The existing no-delivery guard scans every walked location for the tokens matrix and /alerts/, plus the five Task 15 field names and the item-name token alertmanager_matrix_receiver. The new resource necessarily trips it: its Terraform name contains matrix and its itemPath contains alertmanager_matrix_receiver.
The fix is a path-scoped skip, not a token removal — and it suppresses only forbidden-string scanning. The sensitive-resource-type and manifest-kind checks still run over the new resource, which passes them on its own merits because OnePasswordItem is not a sensitive kind. Webhook-key detection and the alternate-config-source checks are likewise untouched, though it is worth being precise that those read the Helm values and the rendered Alertmanager config rather than the Terraform resource, so they never covered this resource to begin with.
Weak links and reviewer notes
No blocking defect was found in the change as scoped. These are the seams a reviewer should hold in mind — each one is a consequence of Task 15 deliberately deferring meaning to Task 16.
MediumThe five-key assertion validates a constant, not the configuration+
validate_source builds source_fields from the left column of FIELD_MAPPING and secret_keys from the right column, then asserts they are equal and number five. Both columns come from the same hardcoded literal of five identical pairs, so the assertion is true by construction and cannot fail.LowThe guard exemption is a substring match on the location path+
.kubernetes_manifest.matrix_alertmanager_receiver appears anywhere in a walked location, so every nested location under that resource is exempt from forbidden-token scanning.policy.py pointing at the pinning assertion would keep the pair from drifting apart.LowThe no-Secret rule guards the Terraform surface, not the cluster surface+
resource_failures blocks core from declaring a kind: Secret manifest, and OnePasswordItem is deliberately absent from the sensitive-kind set — so the new resource passes that check on its own merits, without needing the exemption.InfoThe trusted plan artifact expires 2026-08-19T06:59:59Z+
InfoTrivy was deferred locally; CI static checks carry it+
InfoMerging introduces no content change relative to the head+
052418a0 and merge-preview commit 67cac708 resolve to the same tree, df8fd457.Status
Every automated check that ran on the frozen head passed — Apply and Main Plan were skipped by design, not failed — and the change is tightly scoped to what Task 15 authorises. The hold is not a symptom of a failure; it is the design. Task 16 remains the sole gate that may assert anything about the credentials themselves, and no step in this pull request attempts that assertion.