Skip to main content

Parse OCI IAM policy statements and dynamic group matching rules into JSON-friendly dicts using ANTLR4.

Project description

OCI Lexer Parser

PyPI PyPI Downloads Unit Tests License Issues Forks Stars

Overview

Note this SDK is used in "OCInferno", a tool to be released within the NetSPI repo by end of March for OCI enumeration and mapping.

In the spirit of full transparency, the development of the script was done with the help of LLM coding assistants. The assistant did most of the heavy lifting. As with any open-source tool, make sure that you review the code to understand what its doing before you run it. That said, we've reviewed the code for any potential issues and welcome any changes via PR requests. See Contributing.md at the repo root.

OCI Lexer Parser converts human-readable OCI IAM statements and dynamic group rules into normalized JSON for analysis, testing, or transformation. It is built with built with ANTLR4 and Python.

See Credits below for the original groundwork in the area by Gordon Trevorrow.


At a Glance

Area Details
Statement types ALLOW, DENY, DEFINE, ADMIT, ENDORSE
Verbs and permissions manage, use, read, inspect, plus {PERMISSION} lists
Subjects group, dynamic-group, service, any-user, any-group
Locations tenancy, compartment name, compartment path, compartment OCID
Conditions ANY / ALL clauses, nested groups, same-mode flattening
Dynamic group rules ALL / ANY groups, nested structures, strict LHS paths
Diagnostics raise, report, or ignore error handling
Output normalization DEFINE substitutions, identity domain enrichment, spans

TL;DR Quickstart (SDK)

Parse policy statements:

import json
from oci_lexer_parser import parse_policy_statements

text = "allow group Admins to manage all-resources in tenancy"
statements = parse_policy_statements(text)["statements"]
print(json.dumps(statements[0], indent=2))
# Output:
# {
#   "kind": "allow",
#   "subject": {"type": "group", "values": [{"label": "Admins"}]},
#   "actions": {"type": "verbs", "values": ["manage"]},
#   "resources": {"type": "all-resources", "values": []},
#   "location": {"type": "tenancy", "values": []}
# }

Parse dynamic group rules:

import json
from oci_lexer_parser import parse_dynamic_group_matching_rules

rules = parse_dynamic_group_matching_rules("ALL { resource.type = 'instance' }")["rules"]
print(json.dumps(rules[0], indent=2))
# Output:
# {
#   "mode": "ALL",
#   "level": 1,
#   "expr": {
#     "type": "group",
#     "mode": "all",
#     "items": [
#       {
#         "type": "clause",
#         "node": {
#           "lhs": "resource.type",
#           "op": "eq",
#           "rhs": {"type": "literal", "value": "instance"}
#         }
#       }
#     ]
#   }
# }

Installation

Requires Python 3.10+.

Option A: pip

pip install oci-lexer-parser

Option B: Git clone (recommended for now)

git clone git@github.com:NetSPI/oci-lexer-parser.git
cd oci-lexer-parser
virtualenv .venv && source .venv/bin/activate
pip install -U pip
pip install .

Import name in Python:

import oci_lexer_parser

Verify the CLI:

oci-lexer-parse --help

SDK Examples

Parse Policy Statements

Input:

Allow service faas to read keys in compartment f_compartment where request.operation='GetKeyVersion'

SDK:

from oci_lexer_parser import parse_policy_statements

text = "Allow service faas to read keys in compartment f_compartment where request.operation='GetKeyVersion'"
payload, diagnostics = parse_policy_statements(text, error_mode="report")
print(payload)

Output:

{
  "schema_version": "1.0",
  "statements": [
    {
      "kind": "allow",
      "subject": {"type": "service", "values": [{"label": "faas"}]},
      "actions": {"type": "verbs", "values": ["read"]},
      "resources": {"type": "specific", "values": ["keys"]},
      "location": {"type": "compartment_name", "values": ["f_compartment"]},
      "conditions": {
        "type": "group",
        "mode": "all",
        "items": [
          {
            "type": "clause",
            "node": {
              "lhs": "request.operation",
              "op": "eq",
              "rhs": {"type": "literal", "value": "GetKeyVersion"}
            }
          }
        ]
      }
    }
  ]
}

Parse Dynamic Group Matching Rules

Input:

ALL { instance.compartment.id = 'ocid1.compartment.oc1..example', resource.type = 'instance' }

SDK:

from oci_lexer_parser import parse_dynamic_group_matching_rules

payload = parse_dynamic_group_matching_rules(
    "ALL { instance.compartment.id = 'ocid1.compartment.oc1..example', resource.type = 'instance' }"
)
print(payload)

Output:

{
  "schema_version": "1.0",
  "rules": [
    {
      "level": 1,
      "expr": {
        "type": "group",
        "mode": "all",
        "items": [
          {
            "type": "clause",
            "node": {
              "lhs": "instance.compartment.id",
              "op": "eq",
              "rhs": {"type": "ocid", "value": "ocid1.compartment.oc1..example"}
            }
          },
          {
            "type": "clause",
            "node": {
              "lhs": "resource.type",
              "op": "eq",
              "rhs": {"type": "literal", "value": "instance"}
            }
          }
        ]
      }
    }
  ]
}

Notes:

  • If the rule contains mixed nested modes (for example, ANY { ..., ALL { ... } }), output preserves structure under expr.
  • Same-mode nesting is simplified only when nested_simplify=True.
  • expr is always present; flat rules simply contain only clause items.

Conditions note:

  • Condition RHS values are typed as literal, ocid, or regex (and lists/ranges are composed of those typed values).

CLI Examples

Parse from stdin:

echo "Allow service faas to read keys in compartment f_compartment" | oci-lexer-parse --pretty

Parse a file with diagnostics:

oci-lexer-parse --error-mode report ./policy.txt --pretty

Stream JSON Lines:

oci-lexer-parse ./policy.txt --jsonl

Docs

Document Purpose
docs/CLI_Usage.md CLI flags, output shapes, and examples
docs/Examples.md End-to-end OCI SDK examples with sample output
docs/sdk/Policy_SDK.md Policy SDK usage and diagnostics
docs/sdk/Dynamic_Group_SDK.md Dynamic group SDK usage and diagnostics
docs/schema/Policy_Schema.md Policy statement JSON schema
docs/schema/Dynamic_Group_Schema.md Dynamic group JSON schema
docs/Roadmap.md Expected changes and future improvements
Contributing.md Development workflow and tests
LICENSE.md BSD 3-Clause license text

Dependencies

Runtime dependency:

antlr4-python3-runtime>=4.13.2,<4.14

Contributing

See Contributing.md.


Credits

Author: Webbin Root

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

oci_lexer_parser-0.1.2.tar.gz (56.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

oci_lexer_parser-0.1.2-py3-none-any.whl (60.6 kB view details)

Uploaded Python 3

File details

Details for the file oci_lexer_parser-0.1.2.tar.gz.

File metadata

  • Download URL: oci_lexer_parser-0.1.2.tar.gz
  • Upload date:
  • Size: 56.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for oci_lexer_parser-0.1.2.tar.gz
Algorithm Hash digest
SHA256 4a3171dff580ab3a83e66e535b134a145600855bdd36b7bdc875978efdca1d4b
MD5 81f7fe8338c9055aa860cb11cc13bda2
BLAKE2b-256 5bb631051ddcb4818ddec4e597b2b8c74ee6094cedf59be31f651c6c974f33d7

See more details on using hashes here.

Provenance

The following attestation bundles were made for oci_lexer_parser-0.1.2.tar.gz:

Publisher: publish.yml on NetSPI/oci-lexer-parser

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file oci_lexer_parser-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for oci_lexer_parser-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f2034b48e285941beaad44b4677287f21725498897d1de23c6a1eea934b0c4a4
MD5 83e919ee7547a899a69781188e1fb114
BLAKE2b-256 3e2cae38259e77d9dc62356a16631ccb5578f29203c8e2aa6383fddb0042a910

See more details on using hashes here.

Provenance

The following attestation bundles were made for oci_lexer_parser-0.1.2-py3-none-any.whl:

Publisher: publish.yml on NetSPI/oci-lexer-parser

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page