Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .github/scripts/prepare-deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import json
import os
from pathlib import Path
import re
import subprocess
import sys

Expand All @@ -15,6 +16,16 @@ def gcloud(*args):
return result.stdout


def failure_message(error):
operation = " ".join(error.cmd[1:4])
categories = re.findall(
r"\b(?:PERMISSION_DENIED|NOT_FOUND|INVALID_ARGUMENT|UNAUTHENTICATED|FAILED_PRECONDITION|RESOURCE_EXHAUSTED)\b",
error.stderr or "",
)
category = categories[0] if categories else "unclassified CLI error"
return f"gcloud {operation} failed (exit {error.returncode}, {category}); command output withheld."


def prepare(service, image, config_names, read_secret):
# Export only writable metadata; keep the service's runtime configuration.
manifest = {
Expand Down Expand Up @@ -110,4 +121,4 @@ def read_secret(name, version):
main()
except subprocess.CalledProcessError as error:
# Never print captured command output, which may contain configuration.
sys.exit(f"gcloud failed (exit {error.returncode}); no secret values were logged.")
sys.exit(failure_message(error))
9 changes: 9 additions & 0 deletions .github/scripts/test_prepare_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import json
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
from unittest.mock import Mock, patch
Expand Down Expand Up @@ -95,6 +96,14 @@ def test_secret_access_failure_prevents_any_deployment(self):
self.assertEqual(cli.call_count, 2)
self.assertFalse((Path(directory) / "cloud-run-service.json").exists())

def test_failure_diagnostics_do_not_expose_command_arguments_or_output(self):
error = subprocess.CalledProcessError(1, ["gcloud", "secrets", "versions", "access", "latest", "--secret", "private-name"],
output="private-value", stderr="PERMISSION_DENIED private-value")
message = module.failure_message(error)
self.assertIn("secrets versions access", message)
self.assertIn("PERMISSION_DENIED", message)
self.assertNotIn("private", message)


if __name__ == "__main__":
unittest.main()
Loading