Skip to content
Open
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
Empty file added op-eventer/README.md
Empty file.
51 changes: 51 additions & 0 deletions op-eventer/monitoring/monitoring.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
Parameters:
Mainnet:
ContractAddress: "0xbEb5Fc579115071764c7423A4f12eDde41f106Ed"
PauseEvent: "0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258"
AuthorizedPauseAddresses: ["0x9ba6e03d8b90de867373db8cf1a58d2f7f006b3a"]
Sepolia:
ContractAddress: "0xbEb5Fc579115071764c7423A4f12eDde41f106Ed"
PauseEvent: "0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258"
AuthorizedPauseAddresses: ["0x9ba6e03d8b90de867373db8cf1a58d2f7f006b3a"]

QueriesTemplate:
TransactionPausedByUnauthorizedAddress: |
WITH log_transactions AS (
SELECT DISTINCT transaction_hash
FROM `bigquery-public-data.crypto_ethereum.logs`
WHERE
LOWER(address) = LOWER('$ContractAddress')
AND topics[OFFSET(0)] = "$PauseEvent"
)
SELECT t.hash as MaliciousTX
FROM `bigquery-public-data.crypto_ethereum.transactions` t
INNER JOIN log_transactions l
ON t.hash = l.transaction_hash
WHERE LOWER(t.to_address) NOT IN (SELECT LOWER(addr) FROM UNNEST($AuthorizedPauseAddresses) AS addr)

TransactionPaused: |
WITH log_transactions AS (
SELECT DISTINCT transaction_hash
FROM `bigquery-public-data.crypto_ethereum.logs`
WHERE
LOWER(address) = LOWER('$ContractAddress')
AND topics[OFFSET(0)] = "$PauseEvent"
)
SELECT t.hash as TX
FROM `bigquery-public-data.crypto_ethereum.transactions` t
INNER JOIN log_transactions l
ON t.hash = l.transaction_hash

Checks:
- Path: consumers/metrics.sh
Queries:
Mainnet-TransactionPausedByUnauthorizedAddress:
Parameters: Mainnet
Query: TransactionPausedByUnauthorizedAddress
Priority: P1
Source: "test"
Mainnet-TransactionPaused:
Parameters: Mainnet
Query: TransactionPaused
Priority: P5
Source: "test"
1 change: 1 addition & 0 deletions op-eventer/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
google.cloud.bigquery
43 changes: 43 additions & 0 deletions op-eventer/setup/alerts/op-eventer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
groups:
- name: op-eventer
rules:
- alert: OpEventerP1
expr: increase(opEventer_metric{ priority="P1" }[230m]) > 0
for: 1s
annotations:
summary: OpEventer Emitted Alert"
labels:
team: security
severity: P1
- alert: OpEventerP2
expr: increase(opEventer_metric{ priority="P2" }[230m]) > 0
for: 1s
annotations:
summary: OpEventer Emitted Alert"
labels:
team: security
severity: P2
- alert: OpEventerP3
expr: increase(opEventer_metric{ priority="P3" }[230m]) > 0
for: 1s
annotations:
summary: OpEventer Emitted Alert"
labels:
team: security
severity: P3
- alert: OpEventerP4
expr: increase(opEventer_metric{ priority="P3" }[230m]) > 0
for: 1s
Comment on lines +29 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix incorrect priority labels in P4 and P5 alerts.

The expressions for P4 and P5 alerts are incorrectly using priority="P3" instead of their respective priorities.

-        expr: increase(opEventer_metric{ priority="P3" }[230m]) > 0
+        expr: increase(opEventer_metric{ priority="P4" }[230m]) > 0
-        expr: increase(opEventer_metric{ priority="P3" }[230m]) > 0
+        expr: increase(opEventer_metric{ priority="P5" }[230m]) > 0

Also applies to: 37-38

Comment on lines +29 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix priority mismatch in P4 and P5 alert expressions.

The expressions for P4 and P5 alerts incorrectly check for P3 priority metrics.

-        expr: increase(opEventer_metric{ priority="P3" }[230m]) > 0
+        expr: increase(opEventer_metric{ priority="P4" }[230m]) > 0
-        expr: increase(opEventer_metric{ priority="P3" }[230m]) > 0
+        expr: increase(opEventer_metric{ priority="P5" }[230m]) > 0

Also applies to: 37-38

annotations:
summary: OpEventer Emitted Alert"
labels:
team: security
severity: P4
- alert: OpEventerP5
expr: increase(opEventer_metric{ priority="P3" }[230m]) > 0
for: 1s
annotations:
summary: OpEventer Emitted Alert"
labels:
team: security
severity: P5
5 changes: 5 additions & 0 deletions op-eventer/setup/alerts/setup_alerts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
set -o pipefail -o errexit -o nounset

source ~/alerts_cred.env
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for missing credentials file.

The script should validate that the credentials file exists before attempting to source it.

-source ~/alerts_cred.env
+if [ ! -f ~/alerts_cred.env ]; then
+    echo "Error: ~/alerts_cred.env not found"
+    exit 1
+fi
+source ~/alerts_cred.env
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
source ~/alerts_cred.env
if [ ! -f ~/alerts_cred.env ]; then
echo "Error: ~/alerts_cred.env not found"
exit 1
fi
source ~/alerts_cred.env

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider making the credentials path configurable and validate its existence.

The hardcoded path ~/alerts_cred.env could cause issues in different environments.

-source ~/alerts_cred.env
+ALERTS_CRED_PATH=${ALERTS_CRED_PATH:-"$HOME/alerts_cred.env"}
+if [[ ! -f "$ALERTS_CRED_PATH" ]]; then
+    echo "Error: Credentials file not found at $ALERTS_CRED_PATH" >&2
+    exit 1
+fi
+source "$ALERTS_CRED_PATH"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
source ~/alerts_cred.env
ALERTS_CRED_PATH=${ALERTS_CRED_PATH:-"$HOME/alerts_cred.env"}
if [[ ! -f "$ALERTS_CRED_PATH" ]]; then
echo "Error: Credentials file not found at $ALERTS_CRED_PATH" >&2
exit 1
fi
source "$ALERTS_CRED_PATH"

mimirtool rules diff --namespaces=op-eventer ./op-eventer.yaml
mimirtool rules sync --namespaces=op-eventer ./op-eventer.yaml
Comment on lines +4 to +5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for op-eventer.yaml file.

The script should check if the YAML file exists before attempting to use it with mimirtool.

+if [ ! -f ./op-eventer.yaml ]; then
+    echo "Error: ./op-eventer.yaml not found"
+    exit 1
+fi
 mimirtool rules diff --namespaces=op-eventer ./op-eventer.yaml
 mimirtool rules sync --namespaces=op-eventer ./op-eventer.yaml
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mimirtool rules diff --namespaces=op-eventer ./op-eventer.yaml
mimirtool rules sync --namespaces=op-eventer ./op-eventer.yaml
if [ ! -f ./op-eventer.yaml ]; then
echo "Error: ./op-eventer.yaml not found"
exit 1
fi
mimirtool rules diff --namespaces=op-eventer ./op-eventer.yaml
mimirtool rules sync --namespaces=op-eventer ./op-eventer.yaml

29 changes: 29 additions & 0 deletions op-eventer/setup/consumers/metrics.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash

set -o pipefail -o errexit -o nounset
source ~/op-eventer.env

function log {
echo $(date "+%Y-%m-%d %H:%M:%S") $*
}

function metric {
metric_name=$1
metric_source=$2
metric_value=$3
payload="${metric_name},${metric_source},${metric_value}"

echo "Sending metric: $payload"

curl \
-X POST \
-u $METRICS_USER \
-H "Content-Type: text/plain" \
"$METRICS_URL" \
-d "$payload"
}
source=$1
value=$2
# echo metric "${metric_name}" "source=test" "${value} metric=1"

metric "opEventer" "source=${source}" "${value}"
89 changes: 89 additions & 0 deletions op-eventer/setup/query_exec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import yaml
from string import Template
import sys
import os
from pprint import pprint
from google.cloud import bigquery
import subprocess
import json
import signal
import time

home = os.path.expanduser("~")
credentials_path = f"{
home}/.config/gcloud/application_default_credentials.json"

# Set credentials environment variable
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = credentials_path


def signal_handler(sig, frame):
print('\nExiting gracefully...')
sys.exit(0)


def run_query(query):
client = bigquery.Client()

query_job = client.query(query)
results = query_job.result()

return results
Comment on lines +25 to +31
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for BigQuery client initialization and query execution.

The function should handle potential errors when initializing the client and executing queries.

 def run_query(query):
-    client = bigquery.Client()
+    try:
+        client = bigquery.Client()
+    except Exception as e:
+        print(f"Failed to initialize BigQuery client: {e}")
+        raise
 
-    query_job = client.query(query)
-    results = query_job.result()
+    try:
+        query_job = client.query(query)
+        results = query_job.result()
+    except Exception as e:
+        print(f"Failed to execute query: {e}")
+        raise
 
     return results
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def run_query(query):
client = bigquery.Client()
query_job = client.query(query)
results = query_job.result()
return results
def run_query(query):
try:
client = bigquery.Client()
except Exception as e:
print(f"Failed to initialize BigQuery client: {e}")
raise
try:
query_job = client.query(query)
results = query_job.result()
except Exception as e:
print(f"Failed to execute query: {e}")
raise
return results

Comment on lines +25 to +31
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling for BigQuery operations.

The query execution lacks proper error handling.

 def run_query(query):
     client = bigquery.Client()
-
-    query_job = client.query(query)
-    results = query_job.result()
-
-    return results
+    try:
+        query_job = client.query(query)
+        return query_job.result()
+    except Exception as e:
+        print(f"Error executing query: {e}")
+        return []
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def run_query(query):
client = bigquery.Client()
query_job = client.query(query)
results = query_job.result()
return results
def run_query(query):
client = bigquery.Client()
try:
query_job = client.query(query)
return query_job.result()
except Exception as e:
print(f"Error executing query: {e}")
return []



def send_alert(script_path, source, metric_name, priority, fields):
subprocess.run(f"bash {script_path} '{source}' 'Query={metric_name},Priority={
priority},{fields} metric=1'", shell=True)


def process_queries(config):

# Get all Parameters
Parameters = config['Parameters']
# Get all QueryTemplate
QueriesTemplate = config['QueriesTemplate']
# Process Checks
Checks = config['Checks']

processed_queries = []
for check in Checks:
script_path = check['Path']
queries = check['Queries']
for query in queries:
query_name = query
query_parameters_name = queries[query_name]['Parameters']
query_template_name = queries[query_name]['Query']
priority = queries[query_name]['Priority']
source = queries[query_name]['Source']

query_parameters = Parameters[query_parameters_name]
query_template = Template(QueriesTemplate[query_template_name])
parsed_query = query_template.safe_substitute(query_parameters)
processed_queries.append((query_name, parsed_query))

results = run_query(parsed_query)

for row in results:
field_string = " ".join(
f"{field}={getattr(row, field)}" for field in row.keys())

print(f"\n{field_string} \n")
send_alert(script_path, source, query_name,
priority, field_string)

return processed_queries


if __name__ == "__main__":
signal.signal(signal.SIGINT, signal_handler)
file_path = sys.argv[1]

while True:
with open(file_path, 'r') as file:
config = yaml.safe_load(file)

for name, query in process_queries(config):
print(f"\nProcessing {name} ")
print(query)

time.sleep(10)
26 changes: 26 additions & 0 deletions op-eventer/setup/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash -eo pipefail

# Get script's absolute path
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
VENV_DIR="$SCRIPT_DIR/../../.venv"
MONITORING_DIR="$SCRIPT_DIR/../monitoring"
query_exec="$SCRIPT_DIR/query_exec.py"

# Activate virtual environment
source "$VENV_DIR/bin/activate"

export GOOGLE_CLOUD_PROJECT=oplabs-dev-security
# Check where credentials actually are
CRED_FILE=$(gcloud info --format="get(config.paths.global_config_dir)")/application_default_credentials.json

if [ ! -f "$CRED_FILE" ]; then
echo "No application default credentials found. Running gcloud auth..."
gcloud auth application-default login
else
if ! GOOGLE_APPLICATION_CREDENTIALS="$CRED_FILE" gcloud auth application-default print-access-token &>/dev/null; then
echo "Invalid credentials. Running gcloud auth..."
gcloud auth application-default login
fi
fi

python $query_exec $MONITORING_DIR/monitoring.yaml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for Python script execution.

The script should handle potential failures when executing the Python script.

-python $query_exec $MONITORING_DIR/monitoring.yaml 
+if [ ! -f "$MONITORING_DIR/monitoring.yaml" ]; then
+    echo "Error: $MONITORING_DIR/monitoring.yaml not found"
+    exit 1
+fi
+
+if ! python "$query_exec" "$MONITORING_DIR/monitoring.yaml"; then
+    echo "Error: Failed to execute $query_exec"
+    exit 1
+fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
python $query_exec $MONITORING_DIR/monitoring.yaml
if [ ! -f "$MONITORING_DIR/monitoring.yaml" ]; then
echo "Error: $MONITORING_DIR/monitoring.yaml not found"
exit 1
fi
if ! python "$query_exec" "$MONITORING_DIR/monitoring.yaml"; then
echo "Error: Failed to execute $query_exec"
exit 1
fi