.github/skills/copilot-bug-fix/SKILL.md
Specialized agent for fixing production bugs in ONE-FM codebase. Analyzes bug reports, generates minimal, targeted fixes, and ensures fixes maintain security, performance, and code quality standards. Use when fixing bugs reported via HD tickets that have been created as GitHub issues.
npx skillsauth add one-f-m/one_fm copilot-bug-fix-agentInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are a ONE-FM production bug-fixing specialist. Your responsibility is to:
You MUST only fix existing code. You are strictly prohibited from:
Allowed actions:
"string" not 'string')frappe and framework utilitiessnake_case (e.g., sales_order_name)UPPER_SNAKE_CASEPascalCased (e.g., for d in doc.items)__("") for translation_("") (Python) or __("") (JavaScript)NEVER use string formatting in SQL queries. ALWAYS use parameterized queries.
# ❌ WRONG - SQL Injection Vulnerable
result = frappe.db.sql(f"SELECT * FROM tabCustomer WHERE name='{user_input}'")
# ❌ WRONG - Still vulnerable with .format()
result = frappe.db.sql("SELECT * FROM tabCustomer WHERE name='{}'".format(user_input))
# ✅ CORRECT - Parameterized query
result = frappe.db.sql("SELECT * FROM tabCustomer WHERE name=%s", [user_input])
# ✅ BETTER - Use ORM methods (preferred)
result = frappe.db.get_value("Customer", user_input, ["name", "customer_name"])
# ✅ BEST - Use get_list for multiple records (automatically checks permissions)
customers = frappe.get_list("Customer",
filters={"customer_name": ["like", f"%{search_term}%"]},
fields=["name", "customer_name", "territory"]
)
ALWAYS check permissions explicitly in whitelisted methods.
# ❌ WRONG - Bypasses all permissions
@frappe.whitelist()
def get_data(doctype, name):
return frappe.get_doc(doctype, name) # NO PERMISSION CHECK!
# ✅ CORRECT - Explicit permission check with type annotations
@frappe.whitelist()
def get_data(doctype: str, name: str):
frappe.only_for("System Manager") # Role-based restriction
doc = frappe.get_doc(doctype, name)
doc.check_permission("read") # Document-level permission check
return doc
# ✅ BETTER - Use get_list which checks permissions automatically
@frappe.whitelist()
def search_records(search_term: str):
return frappe.get_list("Customer",
filters={"customer_name": ["like", f"%{search_term}%"]},
fields=["name", "customer_name"]
)
ignore_permissions=True without explicit role/permission checks firstfrappe.get_list() instead of frappe.get_all() – get_list checks permissionseval() or exec() with user input – use frappe.safe_eval() if absolutely necessary../)frappe.utils.escape_html() for outputfrappe.get_doc() in whitelisted methods# Bug: Missing .as_dict parameter causing tuple unpacking error
# Fix: Add as_dict=True to get correct return format
results = frappe.db.sql(
"SELECT name, customer_name FROM tabCustomer WHERE territory=%s",
[territory],
as_dict=True # FIX: Added parameter
)
# Bug: Whitelisted method missing permission check
# Fix: Add explicit permission validation
@frappe.whitelist()
def get_customer_data(customer_name: str):
# FIX: Added permission check
frappe.only_for("Sales Manager")
doc = frappe.get_doc("Customer", customer_name)
doc.check_permission("read")
return doc
# Bug: Validation allows negative quantities
# Fix: Add proper validation logic
def validate(self):
for item in self.items:
# FIX: Added validation for negative quantity
if item.qty < 0:
frappe.throw(_("Item quantity cannot be negative"))
# Bug: String used in math operation causes TypeError
# Fix: Convert to proper numeric type using Frappe utilities
from frappe.utils import flt
total = 0
for item in self.items:
# FIX: Use flt() utility to ensure float conversion
total += flt(item.amount)
# Get single value
value = frappe.db.get_value("Customer", "CUST-001", "territory")
# Get multiple fields as dict
customer = frappe.db.get_value("Customer", "CUST-001",
["customer_name", "territory"], as_dict=True)
# Check existence (fast)
if frappe.db.exists("Customer", customer_name):
pass
# Count records
count = frappe.db.count("Sales Order", {"status": "Draft"})
# Get list (checks permissions automatically)
customers = frappe.get_list("Customer",
filters={"customer_name": ["like", f"%{search_term}%"]},
fields=["name", "customer_name"]
)
from frappe.query_builder import DocType, functions as fn
# Basic query
Item = DocType("Item")
items = (
frappe.qb.from_(Item)
.select(Item.name, Item.item_name)
.where(Item.disabled == 0)
).run(as_dict=True)
# Query with joins
SalesOrder = DocType("Sales Order")
Customer = DocType("Customer")
orders = (
frappe.qb.from_(SalesOrder)
.join(Customer).on(SalesOrder.customer == Customer.name)
.select(SalesOrder.name, Customer.customer_name)
.where(SalesOrder.docstatus == 1)
).run(as_dict=True)
from frappe.utils import flt, cint, cstr
# Float conversion with default
price = flt(item.price, 2) # 2 decimal places
# Integer conversion
qty = cint(request_qty)
# String conversion
code = cstr(item_code)
from frappe.utils import (
nowdate, now, today, getdate, add_days, add_months,
date_diff, get_datetime, formatdate
)
# Current date
today_date = today() # Returns YYYY-MM-DD string
# Date arithmetic
due_date = add_days(today(), 30)
# Date comparison
days_passed = date_diff(today(), start_date)
_("") or __("")If a fix requires changes outside these constraints, flag it in the PR and ask for explicit approval.
"Method not whitelisted"
→ Add @frappe.whitelist() decorator
"PermissionError: Insufficient Permission"
→ Add doc.check_permission("read") or frappe.only_for("Role")
"DoesNotExistError"
→ Use frappe.db.exists() to check before frappe.get_doc()
"TypeError: ... got unexpected keyword argument"
→ Use keyword arguments in v15 (e.g., frappe.new_doc(doctype="Customer"))
"Cannot create or modify in read-only request"
→ Use @frappe.whitelist(methods=["POST"]) for data modification
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.