agentsclimarketplace

Cosec policy author

Skill Ahoo-Wang/skills/plugins/ahoo-cosec-skills/skills/cosec-policy-author

A central aggregation repository for Agent Skills from Ahoo-Wang's open source projects.

Install
npx -y skills add Ahoo-Wang/skills --skill cosec-policy-author

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when writing, validating, explaining, or debugging CoSec policy JSON, policy statements, ALLOW/DENY rules, action matchers, condition matchers, role-based authorization, tenant scoping, or rate limiting policies.

SKILL.md

9.8 KB, as published. Nobody here has run it

CoSec Policy Authoring

This skill helps you write, validate, and explain CoSec security policy JSON files. CoSec uses an AWS IAM-like policy model where policies contain statements that define ALLOW or DENY rules matched against requests.

Policy JSON Structure

A policy file is a single JSON object placed in src/main/resources/cosec-policy/. The file naming convention is *-policy.json.

{
  "id": "unique-policy-id",
  "name": "Human-readable name",
  "category": "optional-category",
  "description": "What this policy does",
  "type": "global",
  "tenantId": "(platform)",
  "condition": { ... },
  "statements": [ ... ]
}

Fields

FieldRequiredDescription
idYesUnique identifier for the policy
nameYesHuman-readable display name
categoryNoLogical grouping label
descriptionNoDetailed description
typeYesglobal (applies to all requests), system (system-level), or custom (user/role-specific)
tenantIdYesTenant scope. Use (platform) for global/system policies
conditionNoPolicy-level ConditionMatcher — if present and doesn't match, entire policy is skipped
statementsYesArray of Statement objects

Statement Structure

Each statement defines a single permission rule:

{
  "name": "StatementName",
  "effect": "allow",
  "action": "...",
  "condition": { ... }
}
FieldRequiredDefaultDescription
nameNoDescriptive name for the statement
effectNo"allow""allow" or "deny". DENY takes precedence over ALLOW
actionYesActionMatcher definition (see below)
conditionNoConditionMatcher definition (see below)

Evaluation Order

  1. Policy-level condition checked first — if it doesn't match, the entire policy returns IMPLICIT_DENY
  2. DENY statements evaluated first — any match returns EXPLICIT_DENY immediately
  3. ALLOW statements evaluated next — any match returns ALLOW
  4. Default: IMPLICIT_DENY

This means you should write DENY rules before ALLOW rules in the statements array for clarity, though the framework handles ordering internally.

Action Matchers

The action field defines which requests a statement applies to. There are several formats:

Simple string — path pattern

"action": "/api/users"

Matches the exact path. Supports Spring path patterns with wildcards and variables.

String with SpEL template

"action": "/user/#{principal.id}/*"

#{principal.id} is evaluated at match time against the current security context principal.

String with path variables

"action": "/user/{id}"

Matches path segments. Access the variable in conditions via request.path.var.id.

Array — multiple paths (OR logic)

"action": ["/auth/register", "/auth/login", "/auth/logout"]

Matches if ANY path in the array matches.

Wildcard

"action": "*"

Matches all requests. Use with conditions to restrict scope.

Object — path matcher with options

"action": {
  "path": {
    "method": "GET",
    "pattern": "/api/users/*",
    "options": {
      "caseSensitive": false,
      "separator": "/",
      "decodeAndParseSegments": false
    }
  }
}

The method field can be a single string or array: "method": ["GET", "POST"].

The pattern field can be a single string or array of patterns.

Object — all matcher with method filter

"action": {
  "all": {
    "method": "GET"
  }
}

Matches all GET requests regardless of path.

Object — composite matcher (OR logic across different matcher types)

"action": {
  "composite": [
    "/api/public/*",
    {
      "path": {
        "method": "POST",
        "pattern": "/api/webhook/*"
      }
    }
  ]
}

Condition Matchers

The condition field adds additional constraints beyond path matching. All condition types:

authenticated — user must be logged in

"condition": { "authenticated": {} }

inRole — user must have the specified role

"condition": { "inRole": { "value": "admin" } }

inTenant — request must be from the specified tenant

"condition": { "inTenant": { "value": "tenant-abc" } }

eq — exact value match

"condition": {
  "eq": {
    "part": "request.path.var.id",
    "value": "#{principal.id}"
  }
}

The part field is a path expression that extracts a value from the request or security context:

  • request.path.var.{name} — path variable
  • request.remoteIp — client IP
  • request.origin — request origin
  • request.method — HTTP method
  • request.attributes.{key} — request attributes (e.g., request.attributes.ipRegion)
  • context.principal.id — current user ID
  • context.principal.attributes.{key} — principal attributes

The value field supports SpEL templates like #{principal.id}.

contains — substring match

"condition": {
  "contains": {
    "part": "request.attributes.ipRegion",
    "value": "上海"
  }
}

startsWith / endsWith — prefix/suffix match

"condition": {
  "startsWith": {
    "part": "request.attributes.ipRegion",
    "value": "中国"
  }
}

in — value must be in a list

"condition": {
  "in": {
    "part": "context.principal.id",
    "value": ["adminId", "developerId"]
  }
}

regular — regex match

"condition": {
  "regular": {
    "negate": true,
    "part": "request.origin",
    "pattern": "^(http|https)://github.com"
  }
}

Set negate: true to invert the match (matches when regex does NOT match).

path — path pattern match on arbitrary values

"condition": {
  "path": {
    "part": "request.remoteIp",
    "pattern": "192.168.0.*",
    "options": {
      "caseSensitive": false,
      "separator": ".",
      "decodeAndParseSegments": false
    }
  }
}

bool — boolean logic (AND/OR)

"condition": {
  "bool": {
    "and": [
      { "authenticated": {} }
    ],
    "or": [
      { "in": { "part": "context.principal.id", "value": ["dev1"] } },
      { "path": { "part": "request.remoteIp", "pattern": "10.0.0.*" } }
    ]
  }
}

All items in and must match. At least one item in or must match. Both are optional — you can use just and, just or, or both.

spel / ognl — expression-based

"condition": {
  "spel": {
    "expression": "#principal.attributes['vip'] == 'true'"
  }
}

rateLimiter — rate limiting

"condition": {
  "rateLimiter": {
    "permitsPerSecond": 10
  }
}

groupedRateLimiter — grouped rate limiting

"condition": {
  "groupedRateLimiter": {
    "permitsPerSecond": 100,
    "groupKey": "context.principal.id"
  }
}

Common Patterns

Public endpoints (no auth required)

{
  "id": "public-api",
  "name": "Public API",
  "type": "global",
  "tenantId": "(platform)",
  "statements": [
    {
      "name": "PublicEndpoints",
      "action": ["/auth/login", "/auth/register", "/health"]
    }
  ]
}

Admin-only endpoints

{
  "id": "admin-api",
  "name": "Admin API",
  "type": "global",
  "tenantId": "(platform)",
  "statements": [
    {
      "name": "AdminOnly",
      "action": "/admin/**",
      "condition": { "inRole": { "value": "admin" } }
    }
  ]
}

User can only access their own resources

{
  "name": "OwnResourcesOnly",
  "action": "/api/users/{id}/**",
  "condition": {
    "eq": {
      "part": "request.path.var.id",
      "value": "#{principal.id}"
    }
  }
}

IP whitelist with deny

{
  "name": "BlockExternalIp",
  "effect": "deny",
  "action": "*",
  "condition": {
    "regular": {
      "negate": true,
      "part": "request.remoteIp",
      "pattern": "^(10\\.0\\.0\\.|192\\.168\\.)"
    }
  }
}

CORS origin restriction

{
  "name": "RestrictOrigin",
  "effect": "deny",
  "action": "*",
  "condition": {
    "regular": {
      "negate": true,
      "part": "request.origin",
      "pattern": "^https://(app\\.example\\.com|admin\\.example\\.com)"
    }
  }
}

Rate-limited authenticated API

{
  "name": "RateLimitedApi",
  "action": "/api/**",
  "condition": {
    "bool": {
      "and": [
        { "authenticated": {} },
        { "rateLimiter": { "permitsPerSecond": 10 } }
      ]
    }
  }
}

Health probe (for Kubernetes)

{
  "id": "(health-probe)",
  "name": "Health Probe",
  "type": "global",
  "tenantId": "(platform)",
  "statements": [
    {
      "name": "actuator",
      "action": [
        "/actuator/health",
        "/actuator/health/readiness",
        "/actuator/health/liveness"
      ]
    }
  ]
}

Validation Checklist

When reviewing a policy, check:

  1. DENY before ALLOW — while the framework handles ordering, writing DENY statements first improves readability
  2. SpEL templates#{principal.id} is valid; {principal.id} is NOT (conflicts with path variables)
  3. Path variables — use {varName} syntax, access via request.path.var.varName in conditions
  4. Wildcard with conditions"action": "*" alone allows everything; always pair with a condition
  5. Negate logicregular matcher has negate field; other matchers don't
  6. Bool structureand and or are sibling fields, not nested
  7. Part paths — must be valid: request.*, context.principal.*, request.path.var.*, request.attributes.*
  8. Policy typeglobal policies apply to all requests; custom policies are attached to specific users/roles

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.