Token导航 LogoToken导航TokenDH.com
研究检索需要联网github未标认证来源可访问许可证需确认审计提醒

erpnext-impl-whitelistederpnext impl 已列入白名单

Agent Skill

erpnext-impl-whitelisted 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

1,071

周安装

46

GitHub Stars

87

下载量

375
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:erpnext-impl-whitelisted(erpnext impl 已列入白名单)
来源仓库:https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package
仓库路径:skills/erpnext-impl-whitelisted
安装命令:
npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package --skill erpnext-impl-whitelisted
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package --skill erpnext-impl-whitelisted

简介

指导 REST API 端点的白名单方法实现,支持访客访问与权限分级控制。

  • 适用于 Codex、Claude、Cursor、Gemini CLI 中暴露安全可控的服务接口。
  • 强调输入验证与输出过滤,避免 SQL 注入或敏感信息泄露风险。
  • 使用前需明确认证机制,并根据业务敏感度设置 allow_guest 参数。
  • erpnext-impl-whitelisted 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

ERPNext Whitelisted Methods - Implementation

This skill helps you determine HOW to implement REST API endpoints. For exact syntax, see erpnext-syntax-whitelisted.

Version: v14/v15/v16 compatible

Main Decision: What Type of API?

┌───────────────────────────────────────────────────────────────────┐
│ WHAT ARE YOU BUILDING?                                            │
├───────────────────────────────────────────────────────────────────┤
│                                                                   │
│ ► Public API (contact forms, status checks)?                      │
│   └── allow_guest=True + strict input validation                  │
│                                                                   │
│ ► Internal API for logged-in users?                               │
│   └── Default (no allow_guest) + permission checks                │
│                                                                   │
│ ► Admin-only API?                                                 │
│   └── frappe.only_for("System Manager")                           │
│                                                                   │
│ ► Document-specific method (on a form)?                           │
│   └── Controller method + frm.call()                              │
│                                                                   │
│ ► Standalone utility API?                                         │
│   └── Separate api.py + frappe.call()                             │
│                                                                   │
└───────────────────────────────────────────────────────────────────┘

→ See references/decision-tree.md for complete guide.


Decision: Where to Put API Code?

WHERE SHOULD YOUR API LIVE?
│
├─► Related to a specific DocType?
│   │
│   ├─► Called from that DocType's form?
│   │   └─► Controller method (doctype/xxx/xxx.py)
│   │       Client: frm.call('method_name', args)
│   │
│   └─► Standalone but DocType-related?
│       └─► Same file or doctype/xxx/xxx_api.py
│           Client: frappe.call('path.to.method', args)
│
├─► General utility API?
│   └─► myapp/api.py or myapp/api/module.py
│       Client: frappe.call('myapp.api.method', args)
│
└─► External integration?
    └─► myapp/integrations/service_name.py
        Often combined with webhooks

Decision: Permission Model

WHO CAN ACCESS THIS API?
│
├─► Anyone (public)?
│   └─► allow_guest=True
│       ⚠️ MUST validate all input
│       ⚠️ MUST rate limit if possible
│       ⚠️ NEVER expose sensitive data
│
├─► Any logged-in user?
│   └─► Default (no allow_guest)
│       Still check document permissions!
│
├─► Specific role(s)?
│   └─► frappe.only_for("Role") or frappe.only_for(["Role1", "Role2"])
│       Throws PermissionError if user lacks role
│
├─► Document-level permission?
│   └─► frappe.has_permission(doctype, ptype, doc)
│       Check before accessing each document
│
└─► Custom permission logic?
    └─► Implement your own checks
        Always deny by default

Quick Implementation Patterns

Pattern 1: Simple Authenticated API

# myapp/api.py
import frappe
from frappe import _

@frappe.whitelist()
def get_customer_balance(customer):
    """Get customer's outstanding balance."""
    # Permission check
    if not frappe.has_permission("Customer", "read", customer):
        frappe.throw(_("Not permitted"), frappe.PermissionError)

    # Fetch data
    balance = frappe.db.get_value("Customer", customer, "outstanding_amount")

    return {"customer": customer, "balance": balance or 0}
// Client call
frappe.call({
    method: 'myapp.api.get_customer_balance',
    args: { customer: 'CUST-00001' }
}).then(r => {
    console.log(r.message.balance);
});

Pattern 2: Public API with Validation

@frappe.whitelist(allow_guest=True, methods=["POST"])
def submit_inquiry(name, email, message):
    """Public contact form - strict validation required."""
    # Validate required fields
    if not all([name, email, message]):
        frappe.throw(_("All fields are required"))

    # Validate email format
    if not frappe.utils.validate_email_address(email):
        frappe.throw(_("Invalid email address"))

    # Sanitize input
    name = frappe.utils.strip_html(name)[:100]
    message = frappe.utils.strip_html(message)[:2000]

    # Create record
    doc = frappe.get_doc({
        "doctype": "Lead",
        "lead_name": name,
        "email_id": email,
        "notes": message,
        "source": "Website"
    })
    doc.insert(ignore_permissions=True)

    return {"success": True, "id": doc.name}

Pattern 3: Role-Restricted API

@frappe.whitelist()
def get_salary_data(employee):
    """HR-only endpoint."""
    # Role check - throws if not HR
    frappe.only_for(["HR Manager", "HR User"])

    return frappe.get_doc("Employee", employee).as_dict()

Pattern 4: Document Controller Method

# In doctype/sales_order/sales_order.py
class SalesOrder(Document):
    @frappe.whitelist()
    def calculate_shipping(self, carrier):
        """Called via frm.call() from form."""
        # Permission already checked by Frappe for doc access
        rate = get_shipping_rate(self.shipping_address, carrier)
        return {"carrier": carrier, "rate": rate}
// Client (in sales_order.js)
frm.call('calculate_shipping', {
    carrier: 'FedEx'
}).then(r => {
    frm.set_value('shipping_amount', r.message.rate);
});

→ See references/workflows.md for 10+ complete workflows.


Critical Security Rules

1. ALWAYS Check Permissions

# ❌ WRONG - exposes all data
@frappe.whitelist()
def get_document(doctype, name):
    return frappe.get_doc(doctype, name).as_dict()

# ✅ CORRECT
@frappe.whitelist()
def get_document(doctype, name):
    if not frappe.has_permission(doctype, "read", name):
        frappe.throw(_("Not permitted"), frappe.PermissionError)
    return frappe.get_doc(doctype, name).as_dict()

2. NEVER Trust User Input in SQL

# ❌ WRONG - SQL injection!
@frappe.whitelist()
def search(term):
    return frappe.db.sql(f"SELECT * FROM tabItem WHERE name LIKE '%{term}%'")

# ✅ CORRECT - parameterized
@frappe.whitelist()
def search(term):
    return frappe.db.sql("""
        SELECT name, item_name FROM tabItem
        WHERE name LIKE %(term)s
        LIMIT 20
    """, {"term": f"%{term}%"}, as_dict=True)

3. VALIDATE All Input for Guest APIs

@frappe.whitelist(allow_guest=True)
def public_api(data):
    # ❌ WRONG - trusts input
    doc = frappe.get_doc(data)
    doc.insert(ignore_permissions=True)

    # ✅ CORRECT - validate everything
    if not isinstance(data, dict):
        frappe.throw(_("Invalid data format"))

    allowed_fields = {"name", "email", "message"}
    clean_data = {k: v for k, v in data.items() if k in allowed_fields}

    # Validate each field...

4. NEVER Expose Sensitive Data in Errors

# ❌ WRONG - leaks internal info
except Exception as e:
    frappe.throw(str(e))

# ✅ CORRECT - generic message, log details
except Exception:
    frappe.log_error(frappe.get_traceback(), "API Error")
    frappe.throw(_("An error occurred. Please try again."))

5. Use ignore_permissions Sparingly

# ❌ WRONG - bypasses all security
@frappe.whitelist()
def get_all_data():
    return frappe.get_all("Salary Slip", ignore_permissions=True)

# ✅ CORRECT - check role first
@frappe.whitelist()
def get_all_data():
    frappe.only_for("HR Manager")  # Verify role first!
    return frappe.get_all("Salary Slip", ignore_permissions=True)

Error Handling Pattern

Standard Error Response

@frappe.whitelist()
def robust_api(param):
    """API with proper error handling."""
    try:
        # Validate input
        if not param:
            frappe.throw(_("Parameter required"), frappe.ValidationError)

        # Check permissions
        if not frappe.has_permission("MyDocType", "read"):
            frappe.throw(_("Not permitted"), frappe.PermissionError)

        # Process
        result = do_something(param)
        return {"success": True, "data": result}

    except frappe.ValidationError:
        raise  # Let Frappe handle (417)
    except frappe.PermissionError:
        raise  # Let Frappe handle (403)
    except frappe.DoesNotExistError:
        frappe.local.response["http_status_code"] = 404
        return {"success": False, "error": "Not found"}
    except Exception:
        frappe.log_error(frappe.get_traceback(), "API Error")
        frappe.local.response["http_status_code"] = 500
        return {"success": False, "error": "Internal error"}

HTTP Status Codes

CodeExceptionWhen to Use
200-Success
201-Created (set manually)
400-Bad request (set manually)
401AuthenticationErrorNot logged in
403PermissionErrorAccess denied
404DoesNotExistErrorNot found
417ValidationErrorValidation failed
409DuplicateEntryErrorDuplicate
500ExceptionServer error

Response Patterns

Simple Return (Most Common)

@frappe.whitelist()
def get_data():
    return {"key": "value"}
# Response: {"message": {"key": "value"}}

List Response

@frappe.whitelist()
def get_items():
    return frappe.get_all("Item", fields=["name", "item_name"], limit=10)
# Response: {"message": [{"name": "...", "item_name": "..."}, ...]}

With Metadata

@frappe.whitelist()
def get_paged_data(page=1, page_size=20):
    offset = (int(page) - 1) * int(page_size)
    total = frappe.db.count("Item")
    items = frappe.get_all("Item", limit=page_size, start=offset)

    return {
        "data": items,
        "total": total,
        "page": page,
        "page_size": page_size,
        "pages": (total + page_size - 1) // page_size
    }

Client Integration

frappe.call() Options

frappe.call({
    method: 'myapp.api.my_method',
    args: { param1: 'value' },

    // UI Options
    freeze: true,                    // Show loading overlay
    freeze_message: __('Loading...'), // Custom message

    // Callbacks
    callback: function(r) {
        if (r.message) { /* success */ }
    },
    error: function(r) {
        // Handle error
    },
    always: function() {
        // Always runs (finally)
    },

    // Other
    async: true,                     // Default true
    type: 'POST'                     // Default POST
});

Async/Await Pattern

async function fetchData() {
    try {
        const r = await frappe.call({
            method: 'myapp.api.get_data',
            args: { id: 123 }
        });
        return r.message;
    } catch (e) {
        frappe.msgprint(__('Error loading data'));
        console.error(e);
    }
}

Reference Files

FileContents
decision-tree.mdComplete API type selection guide
workflows.mdStep-by-step implementation patterns
examples.mdComplete working examples
anti-patterns.mdCommon mistakes to avoid

Version Differences

Featurev14v15v16
@frappe.whitelist()
allow_guest
methods parameter
Type annotation validation
Rate limiting decorator
API v2 endpoints

v15+ Type Validation

# v15+ validates types automatically
@frappe.whitelist()
def typed_api(customer: str, limit: int = 10) -> dict:
    return {"customer": customer, "limit": limit}

v15+ Rate Limiting

from frappe.rate_limiter import rate_limit

@frappe.whitelist(allow_guest=True)
@rate_limit(limit=5, seconds=60)  # 5 calls per minute
def rate_limited_api():
    return {"status": "ok"}

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

35.34%
按下载量换算133

Claude

28.03%
按下载量换算105

Cursor

21.36%
按下载量换算80

Gemini CLI

9.1%
按下载量换算34

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

可疑

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills