Skip to content

Backend and security

A Yukon extension is trusted server code inside a tenant site. Every endpoint, job, webhook, migration, credential, and record type is part of that tenant's security boundary.

Depend on the public surface

For an extension that requires Yukon, declare required_apps = ["yukon_crm"]. The supported Python imports are:

from yukon_crm.extensions import (
    extension_is_enabled,
    require_extension_enabled,
)

Do not import Yukon controllers, internal registries, query implementations, or frontend source. Request a documented contract when the extension needs something the public surface does not expose.

Enforce enablement and permission

Enablement stops new extension work; it is not authorization. Every endpoint must still enforce Frappe roles and document permissions.

from __future__ import annotations

import frappe

from yukon_crm.extensions import require_extension_enabled


@frappe.whitelist(methods=["POST"])
def start_sync(record_name: str) -> dict[str, str]:
    require_extension_enabled("acme_inventory", default_enabled=False)
    frappe.has_permission("Acme Inventory Link", "write", record_name, throw=True)
    frappe.enqueue(
        "acme_inventory.jobs.sync_record",
        queue="short",
        enqueue_after_commit=True,
        record_name=record_name,
    )
    return {"status": "Queued"}

Use GET only for idempotent reads, fully annotate the API, validate every identifier and enum, and return a deliberate payload. Never return raw document fields, secrets, tracebacks, signatures, or customer data that the caller does not need.

Protect external boundaries

  • Store credentials in site configuration, an approved secret manager, or an appropriate encrypted password field. Never return them to the browser.
  • Authenticate webhooks, validate replay windows where available, bound request size, and make event processing idempotent.
  • Enqueue slow work after the database transaction commits.
  • Use bounded timeouts, retries, rate-limit handling, and deterministic deduplication for provider calls.
  • Define what disablement does to work already in flight.
  • Ship schema and data changes as tested, idempotent Frappe patches.

Every source file must be partner-owned, a declared dependency, or a properly licensed adaptation with required notices preserved.