teleo-infrastructure/tests/test_observatory_read_adapter_gcp_plan.py
twentyOne2x 36fe0d3cc2
Some checks are pending
CI / lint-and-test (push) Waiting to run
Harden Observatory private staging deploy gate (#163)
Merge the T2 readiness and least-privilege staging gate. This does not deploy Cloud Run, mutate Cloud SQL, or change production routing.
2026-07-15 09:55:49 +02:00

383 lines
16 KiB
Python

from __future__ import annotations
import json
import shutil
import subprocess
from pathlib import Path
import pytest
import yaml
from ops import check_observatory_read_adapter_gcp_preflight as preflight
ROOT = Path(__file__).resolve().parents[1]
def run_plan(*args: str) -> str:
return subprocess.check_output(
["python3", "ops/plan_observatory_read_adapter_gcp.py", *args],
cwd=ROOT,
text=True,
)
def test_plan_splits_build_deploy_and_runtime_identities() -> None:
plan = json.loads(run_plan())
assert plan["current_tier"] == "T2_unexecuted_least_privilege_packet"
assert plan["identities"] == {
"build": "sa-artifact-builder@teleo-501523.iam.gserviceaccount.com",
"deploy_and_canary": "sa-observatory-deployer@teleo-501523.iam.gserviceaccount.com",
"runtime": "sa-observatory-read-adapter@teleo-501523.iam.gserviceaccount.com",
"database_principal": "sa-observatory-read-adapter@teleo-501523.iam",
}
commands = "\n".join(plan["commands"])
assert "roles/iam.workloadIdentityUser" in commands
assert "roles/iam.serviceAccountUser" in commands
assert "roles/cloudsql.client" in commands
assert "roles/cloudsql.instanceUser" in commands
assert "roles/artifactregistry.reader" in commands
assert "roles/secretmanager.secretAccessor" in commands
assert "subject/repo:living-ip/teleo-infrastructure:ref:refs/heads/main" in plan["github_wif_member"]
assert plan["conditions"]["deployer_wif"].endswith(
"assertion.workflow_ref=='living-ip/teleo-infrastructure/.github/workflows/"
"gcp-observatory-read-adapter.yml@refs/heads/main'"
)
assert plan["github_wif_provider"].endswith("/providers/observatory-read-adapter-main")
assert "roles/run.serviceAgent" in commands
assert "teleo-pgvector-standby" in plan["conditions"]["cloud_sql"]
assert set(plan["deploy_custom_role"]["permissions"]) == {
"run.operations.get",
"run.services.create",
"run.services.get",
"run.services.setIamPolicy",
"run.services.update",
}
assert "roles/run.admin" not in commands
assert "roles/run.developer" not in commands
assert "sa-artifact-builder" not in commands
assert not set(plan["forbidden_deployer_roles"]) & set(commands.split())
assert plan["production_repoint_executed"] is False
def test_shell_packet_is_unexecuted_and_preserves_private_boundaries() -> None:
shell = run_plan("--format", "shell")
assert shell.startswith("# Unexecuted staging packet")
assert "set -euo pipefail" in shell
assert "run.googleapis.com" in shell
assert "--type CLOUD_IAM_SERVICE_ACCOUNT" in shell
assert "openssl rand -hex 32 | tr -d '\\n'" in shell
assert "--data-file=-" in shell
assert "grep -Fxq sa-observatory-read-adapter@teleo-501523.iam" in shell
assert "users create sa-observatory-read-adapter@teleo-501523.iam" in shell
assert "add-iam-policy-binding teleo" in shell
assert "roles/artifactregistry.writer" not in shell
assert "roles/cloudsql.admin" not in shell
assert "Vercel" not in shell
def test_workflow_requires_dedicated_preflight_before_staging_deploy() -> None:
workflow_path = ROOT / ".github" / "workflows" / "gcp-observatory-read-adapter.yml"
workflow = yaml.safe_load(workflow_path.read_text(encoding="utf-8"))
text = workflow_path.read_text(encoding="utf-8")
assert workflow["env"]["BUILD_SERVICE_ACCOUNT"].startswith("sa-artifact-builder@")
assert workflow["env"]["DEPLOY_SERVICE_ACCOUNT"].startswith("sa-observatory-deployer@")
assert workflow["env"]["DEPLOY_WORKLOAD_IDENTITY_PROVIDER"].endswith(
"/providers/observatory-read-adapter-main"
)
assert workflow["jobs"]["deploy-staging"]["needs"] == ["build", "preflight-staging"]
assert "action=preflight_staging" not in text
assert "inputs.action != 'build_only'" in text
assert "EXPECTED_WORKFLOW_REF" in text
assert "${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" in text
assert "docker images describe" in text
assert "2>/dev/null || true" not in text
assert "--no-invoker-iam-check" in text
assert "--allow-unauthenticated" not in text
assert "API_KEY_VERSION" in text
assert "EXPECTED_IMAGE_REF" in text
assert "check_observatory_read_adapter_gcp_preflight.py" in text
assert 'service_account: ${{ env.BUILD_SERVICE_ACCOUNT }}' in text
assert text.count('service_account: ${{ env.DEPLOY_SERVICE_ACCOUNT }}') == 2
assert "positive-redacted.json" in text
assert "redact_observatory_read_adapter_receipt.jq" in text
assert "database_principal == $db_iam_user" in text
assert "canonical_state_unchanged_after_post: true" in text
assert "cmp <(jq -S . positive.json) <(jq -S . after-write-attempt.json)" in text
assert "rm -f positive.json" in text
def test_preflight_private_cloud_sql_and_secret_validators() -> None:
instance = {
"name": "teleo-pgvector-standby",
"region": "europe-west6",
"databaseVersion": "POSTGRES_16",
"settings": {
"databaseFlags": [{"name": "cloudsql.iam_authentication", "value": "on"}],
"ipConfiguration": {
"ipv4Enabled": False,
"privateNetwork": "projects/teleo-501523/global/networks/teleo-staging-net",
},
},
"ipAddresses": [{"type": "PRIVATE", "ipAddress": "10.61.0.3"}],
}
assert preflight.cloud_sql_is_private_and_iam_enabled(json.dumps(instance)) is True
instance["settings"]["ipConfiguration"]["ipv4Enabled"] = True
instance["ipAddresses"].append({"type": "PRIMARY", "ipAddress": "203.0.113.1"})
assert preflight.cloud_sql_is_private_and_iam_enabled(json.dumps(instance)) is False
assert preflight.cloud_sql_iam_user_exists(
json.dumps(
[
{
"name": "sa-observatory-read-adapter@teleo-501523.iam",
"type": "CLOUD_IAM_SERVICE_ACCOUNT",
}
]
)
)
assert preflight.subnet_is_exact(
json.dumps(
{
"name": "teleo-staging-europe-west6",
"region": "https://www.googleapis.com/compute/v1/projects/teleo-501523/regions/europe-west6",
"network": "https://www.googleapis.com/compute/v1/projects/teleo-501523/global/networks/teleo-staging-net",
}
)
)
assert preflight.secret_is_valid("a" * 32) is True
assert preflight.secret_is_valid("too-short") is False
assert preflight.secret_is_valid("a" * 32 + "\n") is False
assert preflight.secret_is_valid(" " + "a" * 32) is False
assert "gha-creds" not in preflight.sanitize_error("/tmp/work/gha-creds-deadbeef.json denied")
def test_preflight_end_to_end_snapshot_retains_no_secret(monkeypatch) -> None:
instance = {
"name": "teleo-pgvector-standby",
"region": "europe-west6",
"databaseVersion": "POSTGRES_16",
"settings": {
"databaseFlags": [{"name": "cloudsql.iam_authentication", "value": "on"}],
"ipConfiguration": {
"ipv4Enabled": False,
"privateNetwork": "projects/teleo-501523/global/networks/teleo-staging-net",
},
},
"ipAddresses": [{"type": "PRIVATE", "ipAddress": "10.61.0.3"}],
}
secret_value = "never-retain-this-secret-value-000000000000"
deployer = "serviceAccount:sa-observatory-deployer@teleo-501523.iam.gserviceaccount.com"
runtime = "serviceAccount:sa-observatory-read-adapter@teleo-501523.iam.gserviceaccount.com"
project_policy = {
"bindings": [
{"role": preflight.PREFLIGHT_ROLE, "members": [deployer]},
{"role": preflight.DEPLOY_ROLE, "members": [deployer]},
{
"role": "roles/cloudsql.client",
"members": [runtime],
"condition": {
"title": "observatory-exact-cloudsql-instance",
"expression": (
"resource.name == 'projects/teleo-501523/instances/teleo-pgvector-standby' "
"&& resource.service == 'sqladmin.googleapis.com'"
),
},
},
{
"role": "roles/cloudsql.instanceUser",
"members": [runtime],
"condition": {
"title": "observatory-exact-cloudsql-instance",
"expression": (
"resource.name == 'projects/teleo-501523/instances/teleo-pgvector-standby' "
"&& resource.service == 'sqladmin.googleapis.com'"
),
},
},
{
"role": "roles/run.serviceAgent",
"members": [
"serviceAccount:service-785938879453@serverless-robot-prod.iam.gserviceaccount.com"
],
},
]
}
deployer_policy = {
"bindings": [
{"role": "roles/iam.workloadIdentityUser", "members": [preflight.DEPLOY_WIF_MEMBER]}
]
}
runtime_policy = {
"bindings": [{"role": "roles/iam.serviceAccountUser", "members": [deployer]}]
}
artifact_policy = {
"bindings": [{"role": "roles/artifactregistry.reader", "members": [deployer]}]
}
secret_policy = {
"bindings": [
{"role": "roles/secretmanager.secretAccessor", "members": [deployer, runtime]},
{"role": "roles/secretmanager.viewer", "members": [deployer]},
]
}
provider = {
"state": "ACTIVE",
"attributeCondition": preflight.DEPLOY_WIF_ATTRIBUTE_CONDITION,
"attributeMapping": {
"google.subject": "assertion.sub",
"attribute.repository": "assertion.repository",
"attribute.ref": "assertion.ref",
"attribute.workflow_ref": "assertion.workflow_ref",
},
}
def fake_run(command: list[str]) -> subprocess.CompletedProcess[str]:
joined = " ".join(command)
stdout = ""
stderr = ""
returncode = 0
if "auth list" in joined:
stdout = "sa-observatory-deployer@teleo-501523.iam.gserviceaccount.com\n"
elif "projects describe" in joined:
stdout = "teleo-501523\n"
elif command[:3] == ["gcloud", "services", "describe"]:
stdout = "ENABLED\n"
elif "workload-identity-pools providers describe" in joined:
stdout = json.dumps(provider)
elif "iam roles describe observatoryStagingPreflight" in joined:
stdout = json.dumps({"includedPermissions": sorted(preflight.PREFLIGHT_PERMISSIONS)})
elif "iam roles describe observatoryStagingDeployer" in joined:
stdout = json.dumps({"includedPermissions": sorted(preflight.DEPLOY_PERMISSIONS)})
elif "projects get-iam-policy" in joined:
stdout = json.dumps(project_policy)
elif f"service-accounts get-iam-policy {preflight.DEPLOY_SERVICE_ACCOUNT}" in joined:
stdout = json.dumps(deployer_policy)
elif f"service-accounts get-iam-policy {preflight.RUNTIME_SERVICE_ACCOUNT}" in joined:
stdout = json.dumps(runtime_policy)
elif "artifacts repositories get-iam-policy" in joined:
stdout = json.dumps(artifact_policy)
elif "secrets get-iam-policy" in joined:
stdout = json.dumps(secret_policy)
elif "run services describe" in joined:
returncode = 1
stderr = "NOT_FOUND: service not found"
elif "service-accounts describe" in joined:
stdout = "sa-observatory-read-adapter@teleo-501523.iam.gserviceaccount.com\n"
elif "networks subnets describe" in joined:
stdout = json.dumps(
{
"name": "teleo-staging-europe-west6",
"region": "https://www.googleapis.com/compute/v1/projects/teleo-501523/regions/europe-west6",
"network": "https://www.googleapis.com/compute/v1/projects/teleo-501523/global/networks/teleo-staging-net",
}
)
elif "networks describe" in joined:
stdout = "teleo-staging-net\n"
elif "sql instances describe" in joined:
stdout = json.dumps(instance)
elif "sql users list" in joined:
stdout = json.dumps(
[
{
"name": "sa-observatory-read-adapter@teleo-501523.iam",
"type": "CLOUD_IAM_SERVICE_ACCOUNT",
}
]
)
elif "secrets versions list" in joined:
stdout = "7\n"
elif "secrets versions access" in joined:
stdout = secret_value
elif "artifacts docker images describe" in joined:
stdout = "{}"
return subprocess.CompletedProcess(command, returncode, stdout=stdout, stderr=stderr)
monkeypatch.setattr(preflight, "run", fake_run)
image_ref = (
"europe-west6-docker.pkg.dev/teleo-501523/teleo/observatory-read-adapter:"
"33399bd9acfa09e4e5409873e86c8c46ac694a8d-29389090997-1@sha256:" + "a" * 64
)
checks = preflight.build_checks(image_ref)
assert checks
assert {check.status for check in checks} == {"pass"}
assert secret_value not in json.dumps([check.__dict__ for check in checks])
def test_malformed_successful_readback_becomes_blocked_check(monkeypatch) -> None:
monkeypatch.setattr(
preflight,
"run",
lambda command: subprocess.CompletedProcess(command, 0, stdout="[]", stderr=""),
)
check = preflight.command_check(
"malformed",
["gcloud", "sql", "instances", "describe"],
preflight.cloud_sql_is_private_and_iam_enabled,
"unexpected",
)
assert check.status == "blocked"
assert check.detail == "invalid_readback:AttributeError"
@pytest.mark.skipif(shutil.which("jq") is None, reason="jq is required")
def test_receipt_redaction_is_an_explicit_allowlist() -> None:
payload = {
"schema": "livingip.observatory-canonical-claim.v1",
"read_only": True,
"provenance": {
"gcp_project": "teleo-501523",
"cloud_sql_instance": "teleo-501523:europe-west6:teleo-pgvector-standby",
"database": "teleo_canonical",
"database_principal": "sa-observatory-read-adapter@teleo-501523.iam",
"authorization_role": "kb_observatory_read",
"transaction_read_only": True,
"write_privileges_denied": True,
"service_revision": "a" * 40,
"future_sensitive_field": "must-not-survive",
},
"canonical": {
"claim": {"id": "claim-1", "type": "fact", "status": "live", "text": "secret claim text"},
"evidence": [{"excerpt": "secret excerpt", "source_url": "https://private.invalid"}],
"edges": [{"direction": "incoming"}, {"direction": "outgoing"}],
},
"proposal_ledger": {
"distinct_from_canonical": True,
"status_counts": {"approved": 1},
"related": [{"proposal_text": "secret proposal"}],
},
}
result = subprocess.run(
["jq", "-f", str(ROOT / "ops" / "redact_observatory_read_adapter_receipt.jq")],
input=json.dumps(payload),
text=True,
capture_output=True,
check=True,
)
redacted = json.loads(result.stdout)
rendered = json.dumps(redacted)
assert set(redacted["provenance"]) == {
"gcp_project",
"cloud_sql_instance",
"database",
"database_principal",
"authorization_role",
"transaction_read_only",
"write_privileges_denied",
"service_revision",
}
assert redacted["canonical"]["evidence_count"] == 1
assert redacted["proposal_ledger"]["related_count"] == 1
for sensitive in (
"must-not-survive",
"secret claim text",
"secret excerpt",
"https://private.invalid",
"secret proposal",
):
assert sensitive not in rendered