Skip to content
Validate Microservice Code logo

Validate Microservice Code

Validate code follows frappe-microservice-lib patterns, security best practices, and framework conventions.

SKILL.md

Full skill instructions

Validate Microservice Code

Check if code follows frappe-microservice-lib patterns and best practices.

When to Use

  • Reviewing code before commit
  • Ensuring security compliance
  • Verifying framework patterns
  • Code quality checks

Instructions

Security Checks

1. Authentication

# ✅ Good
@app.secure_route('/​endpoint', methods=['GET'])
def handler(user):
    pass

# ❌ Bad - no authentication
@app.route('/​endpoint', methods=['GET'])
def handler():
    pass

2. Tenant Isolation

# ✅ Good
tenant_id = get_current_tenant_id()
app.set_tenant_id(tenant_id)
data = app.tenant_db.get_all('DocType')

# ❌ Bad - no tenant isolation
data = frappe.db.get_all('DocType')

3. SQL Injection Prevention

# ✅ Good - parameterized
result = app.tenant_db.sql(
    "SELECT * FROM `tabDocType` WHERE tenant_id = %s AND status = %s",
    (tenant_id, 'Draft'),
    as_dict=True
)

# ❌ Bad - string formatting
result = app.tenant_db.sql(
    f"SELECT * FROM `tabDocType` WHERE tenant_id = '{tenant_id}'"
)

Framework Pattern Checks

1. Tenant Resolution Function

# ✅ Good - proper tenant resolution
def get_current_tenant_id():
    from flask import g
    from frappe_microservice import get_user_tenant_id
    
    if hasattr(g, 'tenant_id') and g.tenant_id:
        return g.tenant_id
    
    if hasattr(g, 'current_user') and g.current_user:
        user_email = g.current_user
        if user_email in ('Guest', 'Administrator'):
            return None
        tenant_id = get_user_tenant_id(user_email)
        if tenant_id:
            g.tenant_id = tenant_id
            return tenant_id
    return None

# ❌ Bad - missing security checks
def get_current_tenant_id():
    return frappe.session.user

2. Database Access

# ✅ Good - uses tenant_db
app.set_tenant_id(tenant_id)
doc = app.tenant_db.get_doc('DocType', name)

# ❌ Bad - uses frappe.db directly
doc = frappe.get_doc('DocType', name)

3. Transaction Management

# ✅ Good - proper transaction handling
try:
    frappe.db.begin()
    doc1 = app.tenant_db.insert_doc('DocType1', data1)
    doc2 = app.tenant_db.insert_doc('DocType2', data2)
    app.tenant_db.commit()
except Exception as e:
    app.tenant_db.rollback()
    raise

# ❌ Bad - no transaction management
doc1 = app.tenant_db.insert_doc('DocType1', data1)
doc2 = app.tenant_db.insert_doc('DocType2', data2)

Code Structure Checks

1. Service Initialization

# ✅ Good - proper initialization
app = create_microservice(
    "service-name",
    get_tenant_id_func=get_current_tenant_id,
    load_framework_hooks=['frappe', 'erpnext']
)

# ❌ Bad - missing tenant function
app = create_microservice("service-name")

2. Error Handling

# ✅ Good - proper error responses
try:
    doc = app.tenant_db.get_doc('DocType', name)
    return {"data": doc.as_dict()}
except frappe.DoesNotExistError:
    return {"error": "Document not found"}, 404
except Exception as e:
    return {"error": str(e)}, 500

# ❌ Bad - no error handling
doc = app.tenant_db.get_doc('DocType', name)
return {"data": doc.as_dict()}

3. Input Validation

# ✅ Good - validates input
data = request.json
if not data:
    return {"error": "No data provided"}, 400
if not data.get('required_field'):
    return {"error": "required_field is required"}, 400

# ❌ Bad - no validation
data = request.json
doc = app.tenant_db.insert_doc('DocType', data)

Controller Pattern Checks

1. Controller Structure

# ✅ Good - proper controller
from frappe_microservice.controller import DocumentController

class SalesOrder(DocumentController):
    def validate(self):
        if not self.customer:
            self.throw("Customer is required")
    
    def before_insert(self):
        if not self.status:
            self.status = 'Draft'

# ❌ Bad - not using DocumentController
class SalesOrder:
    def validate(self):
        pass

2. Controller Registration

# ✅ Good - registers controllers
from frappe_microservice.controller import setup_controllers
setup_controllers(app, "./​controllers")

# ❌ Bad - controllers not registered
# Controllers won't be called

Hook Pattern Checks

1. Hook Registration

# ✅ Good - proper hook registration
@app.tenant_db.on('Sales Order', 'before_insert')
def set_defaults(doc):
    if not doc.status:
        doc.status = 'Draft'

# ❌ Bad - hook not registered with app
def set_defaults(doc):
    pass

2. Hook Error Handling

# ✅ Good - handles errors
@app.tenant_db.on('Sales Order', 'validate')
def validate_order(doc):
    try:
        if not doc.customer:
            frappe.throw("Customer is required")
    except frappe.ValidationError:
        raise
    except Exception as e:
        frappe.log_error(f"Error: {e}")

# ❌ Bad - no error handling
@app.tenant_db.on('Sales Order', 'validate')
def validate_order(doc):
    if not doc.customer:
        raise Exception("Customer is required")

Common Issues to Check

1. Missing tenant_id Setting

# ❌ Bad - forgot to set tenant_id
@app.secure_route('/​endpoint', methods=['GET'])
def handler(user):
    data = app.tenant_db.get_all('DocType')  # Will fail!

# ✅ Good
@app.secure_route('/​endpoint', methods=['GET'])
def handler(user):
    tenant_id = get_current_tenant_id()
    app.set_tenant_id(tenant_id)
    data = app.tenant_db.get_all('DocType')

2. Using frappe.session Directly

# ❌ Bad - direct session access
user = frappe.session.user

# ✅ Good - use injected user
@app.secure_route('/​endpoint', methods=['GET'])
def handler(user):  # user is injected
    pass

3. Missing Commit

# ❌ Bad - no commit
doc = app.tenant_db.insert_doc('DocType', data)
return {"success": True}

# ✅ Good - commits transaction
doc = app.tenant_db.insert_doc('DocType', data)
app.tenant_db.commit()
return {"success": True}

Validation Checklist

  • All endpoints use @app.secure_route
  • Tenant ID is set before database operations
  • All queries use app.tenant_db (not frappe.db)
  • SQL queries are parameterized
  • Transactions are properly managed (begin/​commit/​rollback)
  • Input validation is performed
  • Error handling returns proper HTTP status codes
  • Controllers extend DocumentController
  • Hooks are registered with @app.tenant_db.on()
  • No direct frappe.session access in endpoints

Key Rules

  1. Always authenticate - Use @app.secure_route
  2. Always isolate - Use app.tenant_db
  3. Always validate - Check input and business rules
  4. Always handle errors - Return proper status codes
  5. Always use transactions - For multi-step operations
  6. Never use frappe.db - In microservices
  7. Never use string formatting in SQL - Always parameterize

More Security skills

supabase logo
Security

supabase

Handles the full Supabase workflow from schema changes to deployment, with built-in security guardrails that catch common traps like RLS...

2.7K 308.9K
View

Comprehensive guides and best practices for Neon Serverless Postgres, covering setup, connection methods, authentication, and platform APIs.

98 216.2K
View

Guide for setting up and using Firebase Authentication. Use this skill when the user's app requires user sign-in, user management, or secure data access using auth rules.

462 163.8K
View

A skill to evaluate how secure Firestore security rules are. Use this when Firestore security rules are updated to ensure that the generated rules are extremely secure and robust.

462 127.7K
View

Official skill for integrating Firebase AI Logic (Gemini API) into web applications. Covers setup, multimodal inference, structured output, and security.

462 125.1K
View

Complete Better Auth server and client setup with database adapters, session management, plugins, and security configuration.

222 118.2K
View

Deploy and manage projects on Vercel using token-based authentication. Use when working with Vercel CLI using access tokens rather than interactive login — e.g. "deploy to vercel", "set up vercel", "add environment variables to vercel".

31.9K 116.1K
View
cloudflare logo
Security

cloudflare

Complete Cloudflare platform integration with decision trees for compute, storage, AI, networking, security, and infrastructure-as-code.

3K 110.7K
View

Run Azure compliance and security audits with azqr plus Key Vault expiration checks. Covers best-practice assessment, resource review, policy/compliance validation, and security posture checks. WHEN: compliance scan, security audit, BEFORE running azqr (compliance cli tool), Azure best practices, Key Vault expiration check, expired certificates, expiring secrets, orphaned resources, compliance assessment.

253 103K
View
gws-gmail logo
Security

gws-gmail

Send, read, and manage Gmail messages, drafts, labels, and account settings.

31.2K 78.9K
View

Comprehensive website auditing across 230+ rules in 21 categories including SEO, performance, security, and accessibility.

94 72.3K
View
gws-shared logo
Security

gws-shared

Shared authentication, CLI syntax, and output formatting patterns for gws Google Workspace commands.

31.2K 63.4K
View

Security AI tools

StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
GeoSpy logo
Security

GeoSpy

GeoSpy: Pricing, Features, FAQs, and Alternatives for AI Teams

Free
View

Detect AI-generated voices to protect against audio fraud.

Paid
View

Ensure Your Content's Originality with AI Plagiarism Checker

Freemium
View
Img Upscaler logo
Security

Img Upscaler

Upscale images by 400% without quality loss

Freemium
View
AICheatCheck logo
Security

AICheatCheck

Accurately Detect AI-Generated Content with TheChecker.AI

Free
View
D
Security

Detect GPT

Chrome extension that detects and flags AI-generated content

Free
View