Skip to main content

scpz

CI PyPI Python Downloads Ruff Checked with mypy License: MIT Docs

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

Container images

Images are built from this repository’s Dockerfile (compatible with Docker and Podman) and published when a GitHub Release is published.

Tagging (both registries): each release tag (for example v0.3.0) is always published; latest is updated only for stable releases (not GitHub pre-releases).

  • ghcr.io/tsjnsn/scpz:<release-tag> and ghcr.io/tsjnsn/scpz:latest (GHCR)
  • tsjnsn/scpz:<release-tag> and tsjnsn/scpz:latest (Docker Hub)

GitHub Container Registry

Published to GitHub Container Registry as ghcr.io/tsjnsn/scpz.

Example (optimize a policy file in the current directory):

docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/work" ghcr.io/tsjnsn/scpz:latest optimize policy.json

With Podman:

podman run --rm --user "$(id -u):$(id -g)" -v "$PWD:/work:z" ghcr.io/tsjnsn/scpz:latest optimize policy.json

Docker Hub

Published to Docker Hub as tsjnsn/scpz.

# Pin to a release (recommended in production)
docker pull tsjnsn/scpz:v0.3.0

docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/work" tsjnsn/scpz:v0.3.0 optimize policy.json --dry-run

Build locally

docker build -t scpz:local .
docker run --rm scpz:local --version

Maintainer credentials

The Publish release workflow pushes to GHCR (via GITHUB_TOKEN) and Docker Hub (via repository secrets). Container jobs run only after PyPI publish succeeds so a failed package release does not leave tagged images for an incomplete release. If DOCKERHUB_USERNAME / DOCKERHUB_TOKEN are unset, the Docker Hub job skips with a workflow notice instead of failing the release.

Secret Purpose
DOCKERHUB_USERNAME Docker Hub account with push access to tsjnsn/scpz (must be tsjnsn today; the workflow image name is fixed, not derived from this secret)
DOCKERHUB_TOKEN Docker Hub access token with Read & Write scope for that account

Ensure the Docker Hub repository tsjnsn/scpz exists before the first push.

Usage

Optimize

# Optimize a single file in-place (original saved as policy.json.bak)
scpz optimize policy.json

# Optimize all JSON files in a directory
scpz optimize policies/

# Dry run — show diff + summary without writing
scpz optimize policy.json --dry-run

# Summary only — just show what would change
scpz optimize policy.json --summary-only

# Write to a different file
scpz optimize policy.json --output optimized.json

# Error instead of auto-splitting
scpz optimize policy.json --no-split

Validate

# Validate a single file
scpz validate policy.json

# Validate all JSON files in a directory
scpz validate policies/

Check equivalence

# Ensure optimized output did not broaden permissions (catalog model)
scpz check-equivalence policy.json policy.optimized.json

Optimization Passes

scpz runs the following optimizations in order, repeating until the output stops changing (up to 5 rounds):

  1. Statement merging — Combines statements that share the same Effect, Condition, and Resource into a single statement with a unioned Action list.
  2. 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.
  3. Condition merging — Deduplicates condition values and merges equivalent condition blocks.
  4. Resource ARN optimization — Collapses multiple specific ARNs into wildcard patterns (e.g. role/Admin + role/ReadOnly → role/*).
  5. Redundancy elimination (opt-in) — Removes statements wholly subsumed by another statement in the same policy (Action via wildcards; NotAction only when a non-empty action catalog is configured, mirroring catalog safety for NotAction compression). Enable with redundancyEliminate.enabled: true in scpz.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 print-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 print-schema -o schema/OptimizerConfig.json

License

MIT

Metadata

Release files for scpz 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for scpz 0.3.1
File Size Uploaded
scpz-0.3.1.tar.gz 245.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for scpz 0.3.1
File Interpreter ABI Platform
scpz-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 396.4 kB

Release files / scpz-0.3.1.tar.gz

Download URL scpz-0.3.1.tar.gz
Size 245.7 kB
Tags Source
SHA-256 checksum
How to use checksums
76eb25cbd7db4850c81e4af3381e39d4e291094ee1c8c0fe46299b08b08ffe52
BLAKE2b-256 checksum
How to use checksums
dbdc66b5ea20ee073e413333abb77987b538630381e0de8d78e59f6657190e87
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 24, 2026.

Transparency log

Release files / scpz-0.3.1-py3-none-any.whl

Download URL scpz-0.3.1-py3-none-any.whl
Size 150.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b506b0539212bd45183228462024c49f3843c3d169b333ceca71c160d4cfcfe7
BLAKE2b-256 checksum
How to use checksums
048853bdd589614767c888cc16eb53c30f34b72a37cb9de5ea1dfc939404d233
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.7

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page