Skip to main content

Squillify development is paused indefinitely. Read why, and discover what this experiment achieved. Read the story

MicroSkills Reference

Access Policy Linter

governance.policy_lint

ProductionBounded custom (Class B)Deterministicstrictfastv1.0.0
No network

Overview

You send an access-policy document — rules of subjects, actions, resources, optional conditions, and the algorithm that combines them — and we report where it contradicts itself. Ten findings, each with a fixed severity: opposite effects on a shared tuple, a rule an earlier rule makes unreachable, overlapping conditions, rules that can never fire, wildcards broader than the profile you declared, and references to subjects, actions or resources your dictionary does not define. Findings carry rule identifiers and field paths and never the subject, action, resource or condition value that triggered them, because a lint report gets pasted into tickets. We answer nothing about any single request: no decision comes out of here, and a clean lint predicts nothing about what an evaluator will allow.

An evaluator tells you what happens to one request; it cannot tell you that rule 7 is unreachable because rule 3 already covers it. Shadowing, contradiction and over-broad wildcards are properties of the whole rule set under a precedence order, and you want them before the policy ships, not after an audit finds them.

Reliability

Fully deterministic: the same document gives byte-identical findings, and the ordering is a total one, so nothing shifts between runs. The combining algorithm changes which findings are meaningful — under FIRST_APPLICABLE array order is the precedence, so an earlier rule that covers a later one makes it unreachable, while under DENY_OVERRIDES and ALLOW_OVERRIDES every rule is evaluated and the same pair is a conflict or a duplicate instead. Condition analysis is bounded, not a solver: it intersects numeric ranges and compares value sets over one attribute path, treats contains, starts_with and ends_with as opaque, and any pair it cannot settle produces no finding at all and is counted in undecidedConditionPairs — we would rather publish the size of what we did not decide than dress a guess up as a finding. The operator names we accept are exactly the fourteen an evaluator accepts, held there by a test that compares the two sets, so a document that lints clean here needs no operator rewritten before it is evaluated. Refusals, and what to do about each. GOV_LINT_INPUT_TOO_LARGE means the declared document is past the 65,536-byte inline limit, so split the rule set or shorten your tokens. GOV_LINT_POLICY_INVALID means a field is the wrong shape — a missing effect, a non-string token, a control character in a token, an unknown severityFloor, combiningAlgorithm or defaultDecision member — and the message names the exact path to fix. GOV_LINT_FIELD_UNKNOWN means a property we do not declare turned up somewhere in the request, which we refuse rather than ignore so a stray key can never carry a credential in, so delete it. GOV_LINT_RULE_ID_DUPLICATE means two rules share an id, which would make every finding about them ambiguous, so make the ids unique. GOV_LINT_RULE_LIMIT_EXCEEDED means more than 200 rules arrived, so lint the document in parts. GOV_LINT_TUPLE_LIMIT_EXCEEDED means one rule declares more than 32 tokens in a position, or more than 32768 tuples in total, so split that rule. GOV_LINT_CONDITION_DEPTH_EXCEEDED means a condition nests deeper than 8 levels, so flatten it or express it as a second rule. GOV_LINT_CONDITION_LEAF_LIMIT_EXCEEDED means one condition carries more than 32 comparisons, so split the rule. GOV_LINT_OPERATOR_UNSUPPORTED means an operator name is not one of the fourteen, so correct the name — we never accept a regular expression, a glob or a match expression as one. GOV_LINT_PROFILE_UNSUPPORTED means the profile is not one of the four, so pick the one your review actually applies. GOV_LINT_CHECK_UNSUPPORTED means checks names a code outside the ten in gov-lint-1, so drop it or fix the spelling. GOV_LINT_CATALOGUE_VERSION_UNSUPPORTED means catalogueVersion is not gov-lint-1; a new catalogue will always be an explicit opt-in rather than a silent upgrade under you. GOV_LINT_DICTIONARY_LIMIT_EXCEEDED means a dictionary list is longer than 500 subjects, 500 resources or 200 actions, so trim it to the vocabulary this policy really uses. GOV_LINT_WORK_REFUSED means the tuple count squared went past 25000000 comparisons, and the refusal reports both the projection and the budget, so reduce the tokens per rule or lint fewer rules per call.

Context footprint

Findings plus counters, capped by maxIssues. Your policy is never echoed back, so the response stays small no matter how large the document. A successful call costs 1 execution credit.

When to use it

When you have a rule set and want its contradictions, unreachable rules and over-broad grants named with rule ids and field paths.

When you need to know whether one particular request is allowed, or when your policy is a role-to-permission grant table rather than a subject/action/resource rule set.

Scope

Note
Coherence findings over one access-policy document under a named, versioned rule catalogue you opt into.

Non-goals

  • Does not decide whether any request is permitted — that is identity.evaluate_abac and identity.evaluate_rbac, and nothing here is an authorization answer
  • Does not store, version, publish or distribute your policy
  • Does not accept a subject, an environment or any request context
  • Does not accept the role-grant table shape that identity.evaluate_rbac takes
  • Does not quote a subject, action, resource or condition value back to you
  • Does not certify compliance with any regulation or framework

Properties

IdempotentRetry safeStreaming supportedFile input supportedRequires external service

Capabilities

analysisvalidation

Cost & billing

Flat rate per invocation

MetercallsBillable onsuccessCost per call1 credit

File handling

Accepts file_refProduces file_refMax input64 KB

How we handle your data

Structured input
What this means

This skill only accepts structured technical values such as numbers, booleans, enums, timestamps, or identifiers. It does not process free-form text, files, or documents.

Squillify guarantees
  • Runs inside Squillify
  • This skill runs inside Squillify.
  • Payloads are not sent to an external service by this skill.
  • Squillify does not permanently store submitted payloads.
  • Telemetry records metadata only, not submitted content.
  • Submitted payloads are not used for training.
  • Submitted payloads are not reviewed by humans.
  • This skill does not target sensitive data.
  • The response does not contain submitted content.
Your responsibility

Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.

Read the Microskill Data Handling Policy

Input schema

FieldTypeRequiredDescription
policyobjectYesClosed access-policy document with 1 to 200 rules in precedence order plus combining algorithm and default decision.
dictionaryobjectNoOptional vocabulary the policy may reference; omit a list to switch that undefined-reference check off rather than pass it.
optionsobjectYesRequired lint options naming the wildcard profile plus optional check subset, severity floor, issue cap, and catalogue version.

Output schema

FieldTypeRequiredDescription
issuesarrayYesFindings at or above the severity floor, ordered by rule index then code then related rule.
summaryobjectYesClosed lint counters for rules, tuples compared, issues by severity, suppressed findings, combining algorithm, profile, catalogue, and truncation.

API contract

POST /v1/execute
curl
curl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"governance.policy_lint","input":{"policy":{"rules":[{"id":"allow-finance-read","effect":"ALLOW","subjects":["group:finance"],"actions":["read"],"resources":["ledger:2026"]}]},"options":{"profile":"STRICT_NO_WILDCARD"}}}'
Integrations
TypeScript SDK
import { Squillify } from "@squillify/sdk";

const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });

const { output } = await sq.execute("governance.policy_lint", {"policy":{"rules":[{"id":"allow-finance-read","effect":"ALLOW","subjects":["group:finance"],"actions":["read"],"resources":["ledger:2026"]},{"id":"deny-finance-read","effect":"DENY","subjects":["group:finance"],"actions":["read"],"resources":["ledger:2026"]}],"defaultDecision":"DENY","combiningAlgorithm":"DENY_OVERRIDES"},"options":{"profile":"STRICT_NO_WILDCARD"}});

Errors

CodeHTTPRetryableDescription
VALIDATION_ERROR400NoThe request payload failed schema validation.
UNAUTHORIZED401NoMissing or invalid API key.
SKILL_NOT_ACCESSIBLE403NoThe API key is not granted access to this skill.
SKILL_NOT_AVAILABLE_FOR_PLAN403NoThis skill is not included in your current plan.
PLAN_ELIGIBILITY_UNAVAILABLE503YesPlan eligibility could not be decided. Retry after backoff.
SKILL_NOT_FOUND404NoThe requested skill or version does not exist.
TENANT_RATE_LIMITED429YesRequest rate limit exceeded. Retry after backoff.
QUOTA_EXCEEDED429YesPlan quota exhausted. Retryable once the quota period resets.
EXECUTION_TIMEOUT504YesExecution exceeded the allowed time budget.
GOV_LINT_INPUT_TOO_LARGE429NoA size, quota, rate, or time limit was exceeded.
GOV_LINT_POLICY_INVALID400NoThe request payload failed this skill's input validation.
GOV_LINT_FIELD_UNKNOWN400NoThe request payload failed this skill's input validation.
GOV_LINT_RULE_ID_DUPLICATE400NoThe request payload failed this skill's input validation.
GOV_LINT_RULE_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
GOV_LINT_TUPLE_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
GOV_LINT_CONDITION_DEPTH_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
GOV_LINT_CONDITION_LEAF_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
GOV_LINT_OPERATOR_UNSUPPORTED400NoThe skill does not support the requested variant.
GOV_LINT_PROFILE_UNSUPPORTED400NoThe skill does not support the requested variant.
GOV_LINT_CHECK_UNSUPPORTED400NoThe skill does not support the requested variant.
GOV_LINT_CATALOGUE_VERSION_UNSUPPORTED400NoThe skill does not support the requested variant.
GOV_LINT_DICTIONARY_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
GOV_LINT_WORK_REFUSED429NoA size, quota, rate, or time limit was exceeded.

Other limits

LimitValue
Recommended inline bytes32 KiB

Limitations

  • Does not decide whether any request is permitted — that is identity.evaluate_abac and identity.evaluate_rbac, and nothing here is an authorization answer
  • Does not store, version, publish or distribute your policy
  • Does not accept a subject, an environment or any request context
  • Does not accept the role-grant table shape that identity.evaluate_rbac takes
  • Does not quote a subject, action, resource or condition value back to you
  • Does not certify compliance with any regulation or framework
  • Deciding a live request — send that to an evaluator
  • Linting a role-to-permission grant table, which is a different document shape
  • Looking for a guarantee that a clean document will allow what you expect

How to call

POST /v1/execute (requires authentication)

Request bodyjson
{
  "skillKey": "governance.policy_lint",
  "input": {
    "policy": {
      "rules": [
        {
          "id": "allow-finance-read",
          "effect": "ALLOW",
          "subjects": [
            "group:finance"
          ],
          "actions": [
            "read"
          ],
          "resources": [
            "ledger:2026"
          ]
        },
        {
          "id": "deny-finance-read",
          "effect": "DENY",
          "subjects": [
            "group:finance"
          ],
          "actions": [
            "read"
          ],
          "resources": [
            "ledger:2026"
          ]
        }
      ],
      "defaultDecision": "DENY",
      "combiningAlgorithm": "DENY_OVERRIDES"
    },
    "options": {
      "profile": "STRICT_NO_WILDCARD"
    }
  }
}

Examples

Allow and deny on the same tuple under deny-overrides

Inputjson
{
  "policy": {
    "rules": [
      {
        "id": "allow-finance-read",
        "effect": "ALLOW",
        "subjects": [
          "group:finance"
        ],
        "actions": [
          "read"
        ],
        "resources": [
          "ledger:2026"
        ]
      },
      {
        "id": "deny-finance-read",
        "effect": "DENY",
        "subjects": [
          "group:finance"
        ],
        "actions": [
          "read"
        ],
        "resources": [
          "ledger:2026"
        ]
      }
    ],
    "defaultDecision": "DENY",
    "combiningAlgorithm": "DENY_OVERRIDES"
  },
  "options": {
    "profile": "STRICT_NO_WILDCARD"
  }
}
Expected outputjson
{
  "issues": [
    {
      "code": "POLICY_EFFECT_CONFLICT",
      "severity": "ERROR",
      "ruleId": "deny-finance-read",
      "relatedRuleId": "allow-finance-read",
      "fieldPath": "policy.rules[1].effect",
      "overlapKind": "EXACT"
    }
  ],
  "summary": {
    "ruleCount": 2,
    "tupleTotal": 2,
    "tuplePairsCompared": 1,
    "issueCount": 1,
    "errorCount": 1,
    "warningCount": 0,
    "infoCount": 0,
    "suppressedBelowFloor": 0,
    "undecidedConditionPairs": 0,
    "combiningAlgorithm": "DENY_OVERRIDES",
    "profile": "STRICT_NO_WILDCARD",
    "catalogueVersion": "gov-lint-1",
    "truncated": false
  }
}

Wildcard subject makes a later rule unreachable under first-applicable

Inputjson
{
  "policy": {
    "rules": [
      {
        "id": "allow-any-read",
        "effect": "ALLOW",
        "subjects": [
          "*"
        ],
        "actions": [
          "read"
        ],
        "resources": [
          "ledger:2026"
        ]
      },
      {
        "id": "allow-audit-read",
        "effect": "ALLOW",
        "subjects": [
          "group:audit"
        ],
        "actions": [
          "read"
        ],
        "resources": [
          "ledger:2026"
        ]
      }
    ],
    "combiningAlgorithm": "FIRST_APPLICABLE"
  },
  "options": {
    "profile": "WILDCARD_ALLOWED",
    "maxIssues": 50,
    "severityFloor": "INFO"
  }
}
Expected outputjson
{
  "issues": [
    {
      "code": "POLICY_RULE_SHADOWED",
      "severity": "WARNING",
      "ruleId": "allow-audit-read",
      "relatedRuleId": "allow-any-read",
      "fieldPath": "policy.rules[1]",
      "overlapKind": "SUBJECT_WILDCARD"
    }
  ],
  "summary": {
    "ruleCount": 2,
    "tupleTotal": 2,
    "tuplePairsCompared": 1,
    "issueCount": 1,
    "errorCount": 0,
    "warningCount": 1,
    "infoCount": 0,
    "suppressedBelowFloor": 0,
    "undecidedConditionPairs": 0,
    "combiningAlgorithm": "FIRST_APPLICABLE",
    "profile": "WILDCARD_ALLOWED",
    "catalogueVersion": "gov-lint-1",
    "truncated": false
  }
}
  • Review a rule set before it ships, and catch a rule an earlier one already covers
  • Prove a policy carries no allow/deny contradiction on the same subject, action and resource
  • Hold a policy to a wildcard profile in review, so a broad grant is a finding rather than a habit

Avoid for

  • Deciding a live request — send that to an evaluator
  • Linting a role-to-permission grant table, which is a different document shape
  • Looking for a guarantee that a clean document will allow what you expect

Composable with

Safety & privacy

  • Runs without calling any external service.
  • Your payloads are never stored permanently.
  • Telemetry captures metadata only — never your payload contents.
  • We never train models on your payloads.
  • No human reviews your payloads.

Tags

analysisvalidationgovernancepolicy