Developer Guide

Import from Security Tools

Build a pipeline that pulls data from your existing RMM, SIEM, or GRC tooling and pre-populates your SCH assessments — without sending sensitive asset data to any third-party service.

⚙️ How it works

1

Pull from your tool

Write a script on your own infrastructure that authenticates with your security tool's API and extracts the relevant data. Your API credentials never leave your environment.

2

Map to the schema

Transform the raw data into the SCH pre-fill JSON format. Your script applies the thresholds and decides whether a control is pass, partial, or fail.

3

Import & review

Upload the JSON file in your SCH assessment. Answers are pre-populated for review. You confirm or override each one before running Phronesis analysis.

⚠️

Privacy boundary: The evidence_summary field is the only field that may reach the Phronesis AI Service. It must contain only aggregated, identifier-free text — no hostnames, IP addresses, device names, or usernames. Use evidence_detail and raw_stats for sensitive specifics — these are stored in the Evidence Vault (GCS) and are never transmitted to Phronesis.

📄 Schema reference

Cyber Essentials v3.3

6 controls (Firewalls, Secure Config, Updates, Access Control, Malware, Scope). Question IDs: q1_1q6_4. Recommended sources: NinjaOne, Ninite Pro, Windows Update for Business.

⬇ Download schema

Fields

Field Required Description
assessmentType Required Must be "ce"
generated Required ISO 8601 datetime — used to warn if data is stale
source Optional Free-text identifier for your pipeline (e.g. "ninjone")
questions Required Object keyed by radio name (e.g. q3_1). Each entry contains the fields below.
→ suggested_value Required Radio answer to pre-fill.
pass fail unsure
→ evidence_summary Optional Aggregated, identifier-free summary. Max 500 chars. May reach Phronesis. No hostnames or IPs.
→ evidence_detail Vault only Detailed evidence with identifiers. Stored in Evidence Vault. Never sent to Phronesis.
→ raw_stats Vault only Machine-readable stats object. Stored in Evidence Vault. Never sent to Phronesis.

Example

// ce-prefill.json — generated by your NinjaOne transform script
{
  "assessmentType": "ce",
  "source": "ninjone",
  "generated": "2026-05-13T09:00:00Z",
  "questions": {
    "q3_1": {
      "suggested_value": "pass",
      "evidence_summary": "Automated patching active; 142/142 devices patched within 14 days"
    },
    "q3_2": {
      "suggested_value": "fail",
      "evidence_summary": "87% of endpoints patched for high/critical within 14 days; 18 overdue",
      "evidence_detail": "Overdue: WS-042 (3 patches), WS-107 (1 patch) ...",
      "raw_stats": { "total": 142, "patched_14d": 124, "overdue": 18 }
    },
    "q5_1": {
      "suggested_value": "pass",
      "evidence_summary": "AV active and updated on 142/142 managed endpoints"
    }
  }
}

NCSC Cyber Assessment Framework

4 objectives, 14 principles, 83 questions. Question IDs: caf_{principle}_{n} (e.g. caf_A1a_1, caf_B3_2). Recommended sources: NinjaOne, Qualys, Tenable, Microsoft Sentinel, Splunk.

⬇ Download schema

Fields

FieldRequiredDescription
assessmentTypeRequiredMust be "caf"
generatedRequiredISO 8601 datetime
sourceOptionalPipeline identifier
questionsRequiredObject keyed by CAF radio name (pattern: caf_[A-D][0-9]+[a-z]?_[0-9]+)
→ suggested_value Required
achieved partial not-achieved na
→ evidence_summaryOptionalAggregated summary. Max 500 chars. May reach Phronesis.
→ evidence_detailVault onlySensitive detail. Never sent to Phronesis.
→ raw_statsVault onlyMachine-readable stats. Never sent to Phronesis.

Example

{
  "assessmentType": "caf",
  "source": "qualys",
  "generated": "2026-05-13T09:00:00Z",
  "questions": {
    "caf_B3_1": {
      "suggested_value": "partial",
      "evidence_summary": "Patch management policy exists; 87% of systems patched within SLA"
    },
    "caf_C1a_1": {
      "suggested_value": "partial",
      "evidence_summary": "SIEM ingesting logs from 94% of assets; 6 assets pending onboarding",
      "raw_stats": { "total_assets": 187, "siem_covered": 175 }
    }
  }
}

ISO 27001:2022 ISMS

8 sections, 58 questions covering Clauses 4–10 and Annex A. Question IDs: iso_{section}_{n} (e.g. iso_CL3_1, iso_AA_4). Recommended sources: ServiceNow GRC, Archer, Entra ID, Jira.

⬇ Download schema

Fields

FieldRequiredDescription
assessmentTypeRequiredMust be "iso27001"
generatedRequiredISO 8601 datetime
sourceOptionalPipeline identifier
questionsRequiredObject keyed by ISO radio name (pattern: iso_(CL[1-7]|AA)_[0-9]+)
→ suggested_value Required
implemented partial not-implemented na
→ evidence_summaryOptionalAggregated summary. Max 500 chars. May reach Phronesis.
→ evidence_detailVault onlySensitive detail. Never sent to Phronesis.
→ raw_statsVault onlyMachine-readable stats. Never sent to Phronesis.

Example

{
  "assessmentType": "iso27001",
  "source": "servicenow-grc",
  "generated": "2026-05-13T09:00:00Z",
  "questions": {
    "iso_CL3_1": {
      "suggested_value": "partial",
      "evidence_summary": "Risk register exists; 23 open risks, 8 without treatment plans"
    },
    "iso_AA_4": {
      "suggested_value": "partial",
      "evidence_summary": "Access reviews completed for privileged accounts quarterly; standard users annually only",
      "raw_stats": { "privileged_accounts": 47, "orphaned_accounts": 14 }
    }
  }
}

DORA — Digital Operational Resilience Act

5 pillars, 49 questions covering Articles 5–45. Question IDs: dora_{pillar}_{n} (e.g. dora_P1_1, dora_P2_3). Recommended sources: ServiceNow ITSM, PagerDuty, Jira, BCM tools.

⬇ Download schema

Fields

FieldRequiredDescription
assessmentTypeRequiredMust be "dora"
generatedRequiredISO 8601 datetime
sourceOptionalPipeline identifier
questionsRequiredObject keyed by DORA radio name (pattern: dora_P[1-5]_[0-9]+)
→ suggested_value Required
achieved partial not-achieved na
→ evidence_summaryOptionalAggregated summary. Max 500 chars. May reach Phronesis.
→ evidence_detailVault onlySensitive detail. Never sent to Phronesis.
→ raw_statsVault onlyMachine-readable stats. Never sent to Phronesis.

Example

{
  "assessmentType": "dora",
  "source": "servicenow-itsm",
  "generated": "2026-05-13T09:00:00Z",
  "questions": {
    "dora_P2_1": {
      "suggested_value": "achieved",
      "evidence_summary": "ICT incident classification policy documented; criteria align with DORA Article 18"
    },
    "dora_P2_3": {
      "suggested_value": "partial",
      "evidence_summary": "2 major incidents in past 12 months; 4-hour initial report SLA met on 1 of 2",
      "raw_stats": { "major_incidents_12m": 2, "sla_met": 1 }
    }
  }
}

AI Governance (EU AI Act / ISO 42001 / NIST AI RMF)

6 domains, 42 questions (33 for deployer-only orgs). Question IDs: aig_{domain}_{n} (e.g. aig_D1_1, aig_D3_2). Recommended sources: AWS SageMaker, Azure ML, MLflow, Collibra, Alation.

⬇ Download schema

Fields

FieldRequiredDescription
assessmentTypeRequiredMust be "ai-governance"
generatedRequiredISO 8601 datetime
sourceOptionalPipeline identifier
questionsRequiredObject keyed by AI Gov radio name (pattern: aig_D[1-6]_[0-9]+)
→ suggested_value Required
achieved partial not-achieved na
→ evidence_summaryOptionalAggregated summary. Max 500 chars. May reach Phronesis. No model names or dataset paths.
→ evidence_detailVault onlySensitive MLOps detail. Never sent to Phronesis.
→ raw_statsVault onlyMachine-readable stats. Never sent to Phronesis.

Example

{
  "assessmentType": "ai-governance",
  "source": "azure-ml",
  "generated": "2026-05-13T09:00:00Z",
  "questions": {
    "aig_D3_1": {
      "suggested_value": "achieved",
      "evidence_summary": "Data catalogue maintained; 94% of AI training datasets catalogued with lineage and quality scores",
      "raw_stats": { "total_datasets": 104, "catalogued": 98 }
    },
    "aig_D5_1": {
      "suggested_value": "partial",
      "evidence_summary": "Adversarial robustness testing completed for 6 of 9 production models"
    }
  }
}

SOC Maturity & AI Readiness

7 domains, 70 questions. Question IDs: soc_{domain}{n} (e.g. soc_G1, soc_T4, soc_AI7). Domain prefixes: G, T, P, Pr, S, TOM, AI. Recommended sources: Splunk, Microsoft Sentinel, CrowdStrike, ServiceNow ITSM, ThreatConnect.

⬇ Download schema

Fields

FieldRequiredDescription
assessmentTypeRequiredMust be "soc"
generatedRequiredISO 8601 datetime
sourceOptionalPipeline identifier
questionsRequiredObject keyed by SOC radio name (pattern: soc_(G|T|P|Pr|S|TOM|AI)[0-9]+)
→ suggested_value Required
fully-implemented partially-implemented not-implemented na
→ evidence_summaryOptionalAggregated summary. Max 500 chars. May reach Phronesis. No system names or analyst IDs.
→ evidence_detailVault onlySensitive SOC metrics. Never sent to Phronesis.
→ raw_statsVault onlyMachine-readable stats. Never sent to Phronesis.

Example

{
  "assessmentType": "soc",
  "source": "splunk",
  "generated": "2026-05-13T09:00:00Z",
  "questions": {
    "soc_G1": {
      "suggested_value": "fully-implemented",
      "evidence_summary": "SIEM deployed; ingesting from 100% of critical assets; avg detection-to-alert 4.2 min"
    },
    "soc_AI1": {
      "suggested_value": "partially-implemented",
      "evidence_summary": "SOAR deployed; 8 of 15 target playbooks automated; MTTR reduced 34% since deployment",
      "raw_stats": { "playbooks_target": 15, "playbooks_live": 8, "mttr_reduction_pct": 34 }
    }
  }
}

🔌 Building your pipeline

These are illustrative examples showing the two-layer pattern. The extraction layer is reusable across assessments; only the mapping layer changes per framework.

🖥 NinjaOne → CE & CAF

NinjaOne API Ninite Pro Python
# extract/ninjone.py
def get_patch_status(api_key):
    devices = ninjone_api.get_devices()
    patched = [d for d in devices
               if d.days_since_patch <= 14]
    return {
        "total": len(devices),
        "patched_14d": len(patched),
        "overdue": len(devices) - len(patched)
    }

# map/ce.py
def map_updates(stats):
    pct = stats["patched_14d"] / stats["total"]
    return {
        "suggested_value":
            "pass" if pct >= 0.95 else
            "fail" if pct < 0.80 else "unsure",
        "evidence_summary":
            f"{pct:.0%} of endpoints patched "
            f"within 14 days"
    }

☁️ Splunk / Sentinel → SOC

Splunk API MS Graph Python
# extract/splunk.py
def get_detection_metrics(token):
    return splunk_api.run_search(
        "index=main sourcetype=alerts "
        "| stats avg(triage_mins) as mttr"
    )

# map/soc.py
def map_siem(metrics):
    mttr = metrics["mttr"]
    return {
        "suggested_value":
            "fully-implemented" if mttr < 5 else
            "partially-implemented" if mttr < 15
            else "not-implemented",
        "evidence_summary":
            f"SIEM deployed; avg detection-to-"
            f"alert {mttr:.1f} min"
    }

📋 ServiceNow → ISO 27001

ServiceNow GRC API Python
# extract/servicenow.py
def get_risk_register(instance, token):
    risks = snow_api.get_risks(instance)
    open_risks = [r for r in risks
                  if r.state == "open"]
    no_treatment = [r for r in open_risks
                    if not r.treatment_plan]
    return {
        "open": len(open_risks),
        "no_treatment": len(no_treatment)
    }

# map/iso27001.py  (iso_CL3_1)
def map_risk_register(stats):
    gap = stats["no_treatment"]
    return {
        "suggested_value":
            "implemented" if gap == 0 else
            "partial" if gap <= 5
            else "not-implemented",
        "evidence_summary":
            f"Risk register active; {stats['open']}"
            f" open risks, {gap} without treatment"
    }

Multi-assessment runner

CLI Python
# run.py — generate any assessment
# python run.py --assessment ce \
#   --output ce-prefill.json

import argparse, json, datetime

MAPPERS = {
    "ce":           map_ce,
    "caf":          map_caf,
    "iso27001":     map_iso27001,
    "dora":         map_dora,
    "soc":          map_soc,
    "ai-governance": map_ai_gov,
}

def run(assessment, output):
    raw = extract_all()   # shared extractors
    mapper = MAPPERS[assessment]
    result = {
        "assessmentType": assessment,
        "generated": datetime.datetime.utcnow()
                         .isoformat() + "Z",
        "questions": mapper(raw)
    }
    json.dump(result, open(output, "w"))

Common questions

No. Your NinjaOne, Splunk, or GRC API keys stay on your own infrastructure. SCH only receives the pre-fill JSON file that you explicitly choose to upload — and even then, only suggested_value and evidence_summary fields are used in the assessment. The evidence_detail and raw_stats fields are stored in the Evidence Vault (GCS) and are never sent to the Phronesis AI Service.
You do. Your transform script applies your own thresholds to the raw data and produces the suggested_value. SCH does not enforce thresholds — it accepts whatever label your script produces. The user reviews and can override any pre-filled answer before running analysis. This keeps compliance judgement with your organisation and assessor, not baked into the platform.
Yes. The questions object only needs to contain entries for the questions you want to pre-fill. Any question not included in the file is left blank for manual entry. You can pre-fill the technical controls from tooling and complete the governance/policy questions manually.
Unknown question IDs are silently ignored — they don't cause an error and won't affect the assessment. This means it's safe to generate a comprehensive mapping from your tool and let SCH pick up whatever matches the current assessment version.
Yes — that's the recommended pattern. The extraction layer (API calls to NinjaOne, Splunk, etc.) is written once and shared. The mapping layer is per-assessment. A CLI runner (e.g. python run.py --assessment caf) calls the shared extractors and the relevant mapper, producing the correct output file for whichever assessment you need.

Ready to run your first import?

Download a schema, build your transform script, and pre-populate your assessment in minutes.