Skip to content
Merged
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
7 changes: 3 additions & 4 deletions src/models/rewards_eligibility_oracle.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@ def main(run_date_override: date = None):
"""
Main entry point for the Rewards Eligibility Oracle.
This function:
1. Sets up Google credentials (if not already set up by scheduler)
2. Fetches and processes indexer eligibility data
3. Submits eligible indexers to the blockchain
4. Sends Slack notifications about the run status
1. Fetches and processes indexer eligibility data
2. Submits eligible indexers to the blockchain
3. Sends Slack notifications about the run status

Args:
run_date_override: If provided, use this date for the run instead of today.
Expand Down
3 changes: 3 additions & 0 deletions src/models/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ def initialize(self):
try:
validate_all_required_env_vars()

# Prepare credentials using inline JSON or file paths
credential_manager.prepare_credentials_for_adc()

# Validate credentials early (Fail Fast)
try:
credential_manager.get_google_credentials()
Expand Down
90 changes: 82 additions & 8 deletions src/utils/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,10 @@ def get_google_credentials(self) -> google.auth.credentials.Credentials:
return credentials

except Exception as e:
error_msg = f"Failed to load Google Cloud credentials: {e}"
logger.error(error_msg)
error_msg = (
"Failed to load Google Cloud credentials. Check GOOGLE_APPLICATION_CREDENTIALS configuration."
)
logger.error(f"{error_msg} Error details: {type(e).__name__}")
raise ValueError(error_msg)


Expand Down Expand Up @@ -407,8 +409,14 @@ def _parse_and_validate_credentials_json(self, creds_env: str) -> dict:

return creds_data

except Exception as e:
raise ValueError(f"Invalid credentials JSON: {e}") from e
except json.JSONDecodeError:
raise ValueError("Invalid credentials JSON format. Expected valid JSON string.")
except ValueError:
# Re-raise our own validation errors with their specific messages
raise
except Exception:
# Catch-all for unexpected errors - don't leak credential data
raise ValueError("Invalid or incomplete credentials. Check credentials structure.")


def _setup_user_credentials_from_dict(self, creds_data: dict) -> None:
Expand Down Expand Up @@ -444,8 +452,70 @@ def _setup_service_account_credentials_from_dict(self, creds_data: dict) -> None
logger.info("Successfully loaded service account credentials from environment variable")

# If the credentials creation fails, raise an error
except Exception as e:
raise ValueError(f"Invalid service account credentials: {e}") from e
except Exception:
raise ValueError(
"Invalid service account credentials. Check private_key, client_email, and project_id fields."
)


def prepare_credentials_for_adc(self) -> None:
"""
Prepare Google credentials for Application Default Credentials (ADC).

Supports both inline JSON and file paths:
- Inline JSON: Writes temp file and updates env var
- File path: Validates existence, logs warning if not found

This enables google.auth.default() to work with both credential sources while
maintaining official API usage.

Raises:
ValueError: If inline JSON is invalid or incomplete
"""
creds_env = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS")

# If not set, log warning and return
if not creds_env:
logger.warning("GOOGLE_APPLICATION_CREDENTIALS not set. Will fall back to ADC.")
return

# Inline JSON pattern
if creds_env.strip().startswith("{"):
creds_data = None
try:
# Validate JSON structure
creds_data = self._parse_and_validate_credentials_json(creds_env)

# Write to temp file
temp_path = Path("/tmp/gcp-credentials.json")
with open(temp_path, "w", encoding="utf-8") as f:
json.dump(creds_data, f)

# Set restrictive permissions
temp_path.chmod(0o600)

# Update env var
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = str(temp_path)

logger.info("Prepared inline JSON credentials for ADC")

except ValueError:
# Re-raise our own validation errors
raise

except Exception:
# Catch unexpected errors without leaking credential data
raise ValueError("Failed to prepare inline credentials. Check JSON format and structure.")

finally:
# Clear data from memory
if creds_data:
creds_data.clear()

# File path pattern
elif not Path(creds_env).exists():
logger.warning(f"Credentials file not found: {creds_env}")
logger.warning("Will attempt to use gcloud CLI or other ADC sources")


def setup_google_credentials(self) -> None:
Expand Down Expand Up @@ -477,8 +547,12 @@ def setup_google_credentials(self) -> None:
self._setup_service_account_credentials_from_dict(creds_data.copy())

# If the credentials parsing fails, raise an error
except Exception as e:
raise ValueError(f"Error processing inline credentials: {e}") from e
except ValueError:
# Re-raise our own validation errors
raise
except Exception:
# Catch unexpected errors without leaking credential data
raise ValueError("Error processing inline credentials. Check format and required fields.")

# Clear the credentials from memory
finally:
Expand Down
Loading