Intelligently optimize AWS SCP JSONs to adhere to strict size, statement, and policy count limits.
Project description
scpz
Intelligently optimize AWS Service Control Policy (SCP) JSONs to fit within AWS's strict limits.
AWS SCP Limits
| Constraint | Limit |
|---|---|
| Policy size | 10,240 bytes |
| Statements per SCP | 5 |
| SCPs per target (account/OU) | 10 |
Requirements
Python 3.13 or later.
Installation
pip install scpz
Or with uv (recommended):
uv tool install scpz
Usage
Optimize
# Optimize a single file in-place (original saved as policy.json.bak)
scpz optimize-cmd policy.json
# Optimize all JSON files in a directory
scpz optimize-cmd policies/
# Dry run — show diff + summary without writing
scpz optimize-cmd policy.json --dry-run
# Summary only — just show what would change
scpz optimize-cmd policy.json --summary-only
# Write to a different file
scpz optimize-cmd policy.json --output optimized.json
# Error instead of auto-splitting
scpz optimize-cmd policy.json --no-split
Validate
# Validate a single file
scpz validate policy.json
# Validate all JSON files in a directory
scpz validate policies/
Optimization Passes
scpz runs the following optimizations in order, repeating until the output stops changing (up to 5 rounds):
- Statement merging — Combines statements that share the same Effect, Condition, and Resource into a single statement with a unioned Action list.
- Action wildcard compression — Replaces groups of actions sharing a common prefix with wildcard patterns (e.g.
s3:GetObject+s3:GetBucketPolicy→s3:Get*). Uses the bundled AWS action catalog in conservative mode to avoid scope broadening. - Condition merging — Deduplicates condition values and merges equivalent condition blocks.
- Resource ARN optimization — Collapses multiple specific ARNs into wildcard patterns (e.g.
role/Admin+role/ReadOnly→role/*). - Redundancy elimination (opt-in) — Removes statements wholly subsumed by another statement in the same policy. Enable with
redundancyEliminate.enabled: trueinscpz.yaml.
When a policy still exceeds limits after optimization, scpz automatically splits it into multiple SCP documents (up to 10 per target).
Configuration
Place a scpz.yaml in your project root (scpz walks up from the input file to find it). See examples/scpz.yaml for a fully-annotated reference.
apiVersion: scpz.io/v1alpha1
kind: OptimizerConfig
metadata:
name: default
spec:
optimizer:
actionCompress:
mode: conservative # conservative | aggressive
redundancyEliminate:
enabled: true # opt-in
# Print the JSON Schema for editor validation
scpz schema
Development
# Install with dev dependencies
uv sync --dev
# Run tests
uv run pytest
# Run tests with coverage
uv run pytest --cov=scpz
# Run a specific test file
uv run pytest tests/test_actions.py -v
# Regenerate the committed schema after model changes
uv run scpz schema -o schema/OptimizerConfig.json
License
MIT
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scpz-0.2.3.tar.gz.
File metadata
- Download URL: scpz-0.2.3.tar.gz
- Upload date:
- Size: 191.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b51924259faea66ebc0f927123a9f3af41ef5cd60a7cb28ce81b2e00ce53750a
|
|
| MD5 |
5529d171e654ea1af490086a443abce8
|
|
| BLAKE2b-256 |
20b1ed9287ce5c3dd4110479679cb199b7f842dde87928ba4447bbddc0954b44
|
Provenance
The following attestation bundles were made for scpz-0.2.3.tar.gz:
Publisher:
publish.yml on tsjnsn/scpz
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scpz-0.2.3.tar.gz -
Subject digest:
b51924259faea66ebc0f927123a9f3af41ef5cd60a7cb28ce81b2e00ce53750a - Sigstore transparency entry: 1552608863
- Sigstore integration time:
-
Permalink:
tsjnsn/scpz@29a8fb27f3d96ba848a376ad7852aaa0bfa28468 -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/tsjnsn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@29a8fb27f3d96ba848a376ad7852aaa0bfa28468 -
Trigger Event:
release
-
Statement type:
File details
Details for the file scpz-0.2.3-py3-none-any.whl.
File metadata
- Download URL: scpz-0.2.3-py3-none-any.whl
- Upload date:
- Size: 139.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d118e09ed5db3a3592f6fc7c52d7cccc503d5cd88b93c58ac0760d75e9fb016
|
|
| MD5 |
e4109a07a7b45071050b4f138b44ca31
|
|
| BLAKE2b-256 |
6e78020c989f9632c1e5cf7272c2a812282262f8c30569466be93d405cb840db
|
Provenance
The following attestation bundles were made for scpz-0.2.3-py3-none-any.whl:
Publisher:
publish.yml on tsjnsn/scpz
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scpz-0.2.3-py3-none-any.whl -
Subject digest:
4d118e09ed5db3a3592f6fc7c52d7cccc503d5cd88b93c58ac0760d75e9fb016 - Sigstore transparency entry: 1552608870
- Sigstore integration time:
-
Permalink:
tsjnsn/scpz@29a8fb27f3d96ba848a376ad7852aaa0bfa28468 -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/tsjnsn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@29a8fb27f3d96ba848a376ad7852aaa0bfa28468 -
Trigger Event:
release
-
Statement type: