packages/opencode/src/bundled-skills/grc-compliance/SKILL.md
This skill should be used when the user asks to "GRC", "governance", "risk", "compliance", "audit", "policy", "control", "risk assessment", "SOX", "GDPR", or any ServiceNow GRC development.
npx skillsauth add groeimetai/snow-flow grc-complianceInstall 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.
GRC (Governance, Risk, Compliance) manages organizational policies, risks, and regulatory compliance.
Policy (sn_compliance_policy)
└── Policy Statements
└── Controls (sn_compliance_control)
└── Control Tests
└── Test Results
Risk (sn_risk_risk)
├── Risk Assessment
└── Risk Response
| Table | Purpose |
| ---------------------------- | ------------------- |
| sn_compliance_policy | Compliance policies |
| sn_compliance_control | Controls |
| sn_compliance_control_test | Control tests |
| sn_risk_risk | Risk records |
| sn_audit_engagement | Audit engagements |
// Create compliance policy (ES5 ONLY!)
var policy = new GlideRecord("sn_compliance_policy")
policy.initialize()
// Basic info
policy.setValue("name", "Information Security Policy")
policy.setValue("description", "Enterprise information security requirements")
policy.setValue("short_description", "InfoSec Policy")
// Classification
policy.setValue("category", "security")
policy.setValue("type", "corporate")
// Owner
policy.setValue("owner", policyOwnerSysId)
policy.setValue("owning_group", securityTeamSysId)
// Status
policy.setValue("state", "draft")
// Dates
policy.setValue("effective_date", "2024-01-01")
policy.setValue("review_date", "2025-01-01")
policy.insert()
// Transition policy state (ES5 ONLY!)
function transitionPolicy(policySysId, newState, notes) {
var policy = new GlideRecord("sn_compliance_policy")
if (!policy.get(policySysId)) {
return { success: false, message: "Policy not found" }
}
var validTransitions = {
draft: ["review", "retired"],
review: ["approved", "draft"],
approved: ["published", "draft"],
published: ["review", "retired"],
retired: ["draft"],
}
var currentState = policy.getValue("state")
if (!validTransitions[currentState] || validTransitions[currentState].indexOf(newState) === -1) {
return { success: false, message: "Invalid transition" }
}
policy.setValue("state", newState)
if (newState === "published") {
policy.setValue("published_date", new GlideDateTime())
}
if (notes) {
policy.work_notes = notes
}
policy.update()
return { success: true, state: newState }
}
// Create compliance control (ES5 ONLY!)
var control = new GlideRecord("sn_compliance_control")
control.initialize()
// Basic info
control.setValue("name", "Access Control Review")
control.setValue("description", "Quarterly review of user access rights")
control.setValue("short_description", "Access Review Control")
// Link to policy
control.setValue("policy", policySysId)
// Classification
control.setValue("type", "detective") // preventive, detective, corrective
control.setValue("category", "access_control")
control.setValue("frequency", "quarterly")
// Owner
control.setValue("owner", controlOwnerSysId)
// Testing
control.setValue("test_frequency", "quarterly")
control.setValue("test_type", "manual")
// Status
control.setValue("state", "draft")
control.insert()
// Create control test (ES5 ONLY!)
function createControlTest(controlSysId, testData) {
var test = new GlideRecord("sn_compliance_control_test")
test.initialize()
test.setValue("control", controlSysId)
test.setValue("name", testData.name)
test.setValue("description", testData.description)
// Test details
test.setValue("test_type", testData.type) // design, operating
test.setValue("planned_start", testData.plannedStart)
test.setValue("planned_end", testData.plannedEnd)
// Assignment
test.setValue("assigned_to", testData.tester)
// Status
test.setValue("state", "open")
return test.insert()
}
// Record test result
function recordTestResult(testSysId, result) {
var test = new GlideRecord("sn_compliance_control_test")
if (!test.get(testSysId)) {
return false
}
test.setValue("state", "closed")
test.setValue("result", result.outcome) // pass, fail, not_tested
test.setValue("actual_end", new GlideDateTime())
test.setValue("findings", result.findings)
test.setValue("evidence", result.evidence)
// If failed, create issue
if (result.outcome === "fail") {
createComplianceIssue(test, result)
}
test.update()
return true
}
// Create risk record (ES5 ONLY!)
var risk = new GlideRecord("sn_risk_risk")
risk.initialize()
// Basic info
risk.setValue("name", "Data Breach Risk")
risk.setValue("description", "Risk of unauthorized access to customer data")
risk.setValue("short_description", "Data Breach")
// Classification
risk.setValue("category", "security")
risk.setValue("subcategory", "data_protection")
// Risk assessment
risk.setValue("inherent_likelihood", 3) // 1-5 scale
risk.setValue("inherent_impact", 5) // 1-5 scale
// Inherent risk = likelihood x impact
// Controls that mitigate this risk
risk.setValue("controls", controlSysIds) // Comma-separated
// Residual risk (after controls)
risk.setValue("residual_likelihood", 2)
risk.setValue("residual_impact", 5)
// Owner
risk.setValue("owner", riskOwnerSysId)
// Status
risk.setValue("state", "assess")
risk.insert()
// Calculate risk score (ES5 ONLY!)
function calculateRiskScore(likelihood, impact) {
var score = likelihood * impact
var rating = "low"
if (score >= 20) {
rating = "critical"
} else if (score >= 12) {
rating = "high"
} else if (score >= 6) {
rating = "medium"
}
return {
score: score,
rating: rating,
}
}
// Assess risk and update record (ES5 ONLY!)
function assessRisk(riskSysId, assessment) {
var risk = new GlideRecord("sn_risk_risk")
if (!risk.get(riskSysId)) {
return false
}
// Update inherent risk
risk.setValue("inherent_likelihood", assessment.inherentLikelihood)
risk.setValue("inherent_impact", assessment.inherentImpact)
var inherentScore = calculateRiskScore(assessment.inherentLikelihood, assessment.inherentImpact)
risk.setValue("inherent_risk_score", inherentScore.score)
risk.setValue("inherent_risk_rating", inherentScore.rating)
// Update residual risk
risk.setValue("residual_likelihood", assessment.residualLikelihood)
risk.setValue("residual_impact", assessment.residualImpact)
var residualScore = calculateRiskScore(assessment.residualLikelihood, assessment.residualImpact)
risk.setValue("residual_risk_score", residualScore.score)
risk.setValue("residual_risk_rating", residualScore.rating)
// Assessment metadata
risk.setValue("assessed_date", new GlideDateTime())
risk.setValue("assessed_by", gs.getUserID())
risk.setValue("state", "monitor")
risk.update()
return true
}
// Create audit engagement (ES5 ONLY!)
var audit = new GlideRecord("sn_audit_engagement")
audit.initialize()
audit.setValue("name", "Q1 2024 SOX Audit")
audit.setValue("description", "Quarterly SOX compliance audit")
audit.setValue("type", "compliance")
// Dates
audit.setValue("planned_start", "2024-01-15")
audit.setValue("planned_end", "2024-02-15")
// Scope
audit.setValue("scope", "Financial controls, access management")
// Team
audit.setValue("lead_auditor", auditorSysId)
audit.setValue("audit_team", auditTeamSysId)
// Status
audit.setValue("state", "planning")
audit.insert()
// Create audit finding (ES5 ONLY!)
function createAuditFinding(auditSysId, findingData) {
var finding = new GlideRecord("sn_audit_finding")
finding.initialize()
finding.setValue("engagement", auditSysId)
finding.setValue("title", findingData.title)
finding.setValue("description", findingData.description)
// Severity
finding.setValue("severity", findingData.severity) // critical, high, medium, low
// Related control
if (findingData.control) {
finding.setValue("control", findingData.control)
}
// Recommendation
finding.setValue("recommendation", findingData.recommendation)
// Owner for remediation
finding.setValue("owner", findingData.owner)
// Due date for remediation
finding.setValue("due_date", findingData.dueDate)
finding.setValue("state", "open")
return finding.insert()
}
// Get compliance summary (ES5 ONLY!)
function getComplianceSummary() {
var summary = {
policies: { total: 0, published: 0, review_needed: 0 },
controls: { total: 0, effective: 0, failed: 0 },
risks: { critical: 0, high: 0, medium: 0, low: 0 },
audits: { open: 0, findings: 0 },
}
// Policies
var ga = new GlideAggregate("sn_compliance_policy")
ga.addAggregate("COUNT")
ga.groupBy("state")
ga.query()
while (ga.next()) {
var count = parseInt(ga.getAggregate("COUNT"), 10)
summary.policies.total += count
if (ga.getValue("state") === "published") {
summary.policies.published = count
}
}
// Risks by rating
ga = new GlideAggregate("sn_risk_risk")
ga.addQuery("active", true)
ga.addAggregate("COUNT")
ga.groupBy("residual_risk_rating")
ga.query()
while (ga.next()) {
var rating = ga.getValue("residual_risk_rating")
var riskCount = parseInt(ga.getAggregate("COUNT"), 10)
if (summary.risks.hasOwnProperty(rating)) {
summary.risks[rating] = riskCount
}
}
return summary
}
| Tool | Purpose |
| --------------------------------- | --------------------- |
| snow_query_table | Query GRC tables |
| snow_execute_script_with_output | Test GRC scripts |
| snow_audit_compliance | Run compliance audits |
| snow_assess_risk | Risk assessment |
// 1. Query active policies
await snow_query_table({
table: "sn_compliance_policy",
query: "state=published",
fields: "name,category,effective_date,review_date",
})
// 2. Find high risks
await snow_query_table({
table: "sn_risk_risk",
query: "residual_risk_rating=high^ORresidual_risk_rating=critical",
fields: "name,category,residual_risk_score,owner",
})
// 3. Get compliance summary
await snow_execute_script_with_output({
script: `
var summary = getComplianceSummary();
gs.info(JSON.stringify(summary));
`,
})
development
This skill should be used when the user asks to "App Engine Studio", "workspace builder", "custom workspace", "AES", "low code", "app development", "studio", or any ServiceNow App Engine Studio development.
tools
This skill should be used when the user asks to "create a widget", "build a widget", "service portal widget", "sp_widget", "fix widget", "widget not working", "ng-click not working", or any Service Portal widget development.
development
This skill should be used when the user asks to "create chatbot", "virtual agent", "VA topic", "NLU", "conversation", "chat flow", "topic block", or any ServiceNow Virtual Agent development.
development
This skill should be used when the user asks to "vendor", "supplier", "contract", "procurement", "SLA", "vendor risk", "vendor performance", or any ServiceNow Vendor Management development.